Exploring Subsetted or Grouped Data
Last week, we explored how your data was defined, how it was categorized, and how missing values were represented. Through this exercise, we were able to develop a general overview of the observations, variables, and values in our datasets. Knowing this we likely have a better sense of areas we want to be able to zoom into and explore in our data. We also sometimes want to be able to zoom out - summarizing something across groups of observations in our data. As we prepare to visualize variation and co-variation in the dataset, let’s first go over how we can both zoom in and zoom out on our datasets.
Zooming in - Exploring Filtered Categorical Data
Filtering to a Category
Filtering is one way we can zoom in on our data - exploring only those observations that meet a particular criteria.
For instance, last week we learned above that one criteria for being designated as a Critical Access Hospital is that the hospital must have 25 or fewer inpatient beds. We may want to see how the values for BEDS change when we filter to (or zoom into) just those observations representing critical access hospitals. Notice how we can combine any number of dplyr verbs using the pipe (%>%). Below I will filter to rows that meet a criteria and then select a variable to examine from the filtered data.
#Run this code chunk.
#df %>% filter(CATEGORICAL_VARIABLE == "VALUE") %>% select(CATEGORICAL_VARIABLE)
hospitals %>% filter(TYPE == "CRITICAL ACCESS") %>% select(NAME, BEDS)
hospitals %>% filter(TYPE == "CRITICAL ACCESS") %>% select(BEDS) %>% summary()
BEDS
Min. : 3.0
1st Qu.: 22.0
Median : 25.0
Mean : 27.7
3rd Qu.: 25.0
Max. :286.0
NA's :42
We can see that there are some hospitals in the US that have been designated as critical access hospitals that have more than 25 beds. Since this does not align with the criteria for critical access hospitals that we discovered in our research, it is likely something that we will want to investigate further.
Filtering to Numeric Observations Above or Below a Threshold
We may also want to see which states have hospitals with more than 1200 beds. To do so, we would filter the data to those observations where BEDS is greater than 1200. The first time I do this below, I select() the NAME of the hospital and the STATE. This shows every hospital with more than 1200 beds, along with the STATE in which it is located. However, what if I only wanted to know which states had hospitals with more than 1200 beds? I wouldn’t necessarily want to select() STATE in this case because this would show me the state for every observation in my filtered data. As you can see below, this means that CA would appear 7 times! Instead, I would want to check the distinct() STATES in the filtered data. Check out how I do this below.
#Run this code chunk.
#df %>% filter(NUMBERIC_VARIABLE > VALUE) %>% distinct(CATEGORICAL_VARIABLE)
#Lists name and state of hospitals with more than 1200 beds.
hospitals %>% filter(BEDS > 1200) %>% select(NAME, STATE)
#Lists state for every hospital with more than 1200 beds in the dataset
hospitals %>% filter(BEDS > 1200) %>% select(STATE)
#Lists the states wtih more than 1200 beds
hospitals %>% filter(BEDS > 1200) %>% distinct(STATE)
Zooming out - aka grouping common values and summarizing
At times, we are seeking to get a broader picture of what’s going on in our dataset than provided - grouping observations that share a common value and then performing a calculation to summarize something within each of those groups. In other words, sometimes we want to see our data in aggregate. For instance, I may want to know the total number of hospital beds per state. To calculate this, I would need to group all of the hospital observations by state and then sum the total number of beds in each group. In such cases, we can call group_by() to aggregate the observations with common variable values into groups. Then we will call summarize() to perform a calculation within each of those groups. summarize() takes a set of values and a calculation method and returns a single value. For instance, if we call summarize() with a numeric column in our dataset and “mean” as a calculation method, it will return the average of all the numeric values in that column. When called in conjunction with group_by(), summarize() takes a set of values for each group and a calculation method and returns a single value for each group.
For the hospitals dataset, we will group the observations by STATE and then use summarize to calculate the sum of BEDS per state. Notice below how we are choosing to ignore NA values above by calling na.rm = TRUE. When we do so, we need to keep in mind that we are not summarizing across all observations in the dataset, but only those for which there is a value listed in the variable we are operating on. Because of this, I also calculate the number of observations in each group, the number of observations where the BEDS variable is missing, and the percentage of observations in the group where the variable is missing. This provides important context for how readily we can rely on these numbers. For instance, when you run the code below, note how in Alaska, the number of beds are missing for 28% of the observations.
#Run this code chunk.
#df %>% group_by(CATEGORICAL_VARIABLE) %>% summarize(NEW_VARIABLE_NAME = sum(NUMBERIC_VARIABLE, na.rm = TRUE)) %>% ungroup()
hospitals %>%
group_by(STATE) %>% #Group observations by state
summarize(
STATES_BEDS = sum(BEDS, na.rm = TRUE), #Calculate the sum of BEDS within each STATE group
OBSERVATIONS = n(), #Calculate how many observations are in each STATE group
MISSING_BEDS = sum(is.na(BEDS)), #Calculate how many NAs are in the BEDS variable in each STATE group
PERCENT_MISSING = sum(is.na(BEDS))/n()*100) %>% #Divide the two values you just calculated to determine the percent of missing data
ungroup()
Notice that I close each of these calls with ungroup(). When we group_by() a variable, any subsequent function calls will continue to be performed on the grouped data, unless we ungroup() it. This can be important if we want to filter to specific values after we summarize() the data. Assuming that we don’t want to perform a filter operation within each group but on the entire new dataframe created after summarizing, we need to ungroup() the data before performing the filter() operation.
From this function, we see the number of beds across all hospitals per state. Depending on the question we are asking, this may or may not be relevant. For instance, if I’m wondering how much hospital infrastructure is available to support Covid-19 patients, one (of a number of factors) I need to consider before presenting this data is which types of hospitals are accepting Covid-19 patients. Are rehabilitation hospitals accepting patients? Psychiatric hospitals? Military hospitals? If they aren’t now, will they at some point? Further, some states are talking about cordoning off hotels for Covid-19 patients. How do we account for this change in the number of hospital beds (something definitely not represented in our data based on the way hospital has been defined). We need to do external research to answer these questions. Then we may wish to filter our data to relevant hospital types. For instance, at this moment, we may filter our data to only include beds at General Acute Care Hospitals. We also know that some hospitals in the dataset are closed. We need to also filter these out before presenting the data. Notice how below, I can do this by simply copying and pasting the code from above and adding one filter statement before grouping the data.
#Run this code chunk.
hospitals %>%
filter(TYPE == "GENERAL ACUTE CARE" & STATUS == "OPEN") %>%
group_by(STATE) %>% #Group observations by state
summarize(
STATES_BEDS = sum(BEDS, na.rm = TRUE), #Calculate the sum of BEDS within each STATE group
OBSERVATIONS = n(), #Calculate how many observations are in each STATE group
MISSING_BEDS = sum(is.na(BEDS)), #Calculate how many NAs are in the BEDS variable in each STATE group
PERCENT_MISSING = sum(is.na(BEDS))/n()*100) %>% #Divide the two values you just calculated to determine the percent of missing data
ungroup()
In other words, often times to answer questions within a dataset, we need to both zoom in and out on data - honing in on certain observations and then generalizing across them. We cannot answer questions well if we don’t have a good understanding of what’s included in our data and how issues are defined. Had we not known that hospitals that are closed and hospitals that are classed as rehabs or psychiatric facilities were included in the data, we may have made some poor assumptions about the number of beds available. Also note how, in every step of data analysis, we have to make decisions about what to include and what to exclude in the analysis. Data analysts play a very active role in shaping the knowledge that gets produced from data. The numbers can never speak for themselves.
When I Need to Zoom In or Out
For some of you, these functions will be necessary to employ before performing operations across numeric variables in your dataset. This is because, as we learned last week, some of you have observational units that span multiple time periods, multiple geographies, or multiple issues. Before performing an operation across a numeric variable, we need to ensure all of the values in that variable are referring to observations reported across the same timeframe or geographic scale.
In the hospitals dataset, this is less of a concern because as we learned last week, the observational unit of the dataset is one thing without qualifiers - a hospital. The BEDS variable is always going to refer to the number of BEDS at a hospital.
With the world_health_econ data, we learned last week that every observation refers to a country and a year. Let’s say that we wanted to call summary() on life_exp variable to compare life expectancies across countries. Without first zooming in to to a specific year, we would be including multiple values taken at the same place at different times. Let’s filter the data to only include the most recent reporting year and then call summary():
#Run this code chunk.
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>% #Note that this is how we can fliter to the rows with the maximum value in a variable; in this case, this would be the most recent year.
select(life_exp) %>%
summary()
life_exp
Min. :32.50
1st Qu.:63.95
Median :73.35
Mean :70.52
3rd Qu.:77.05
Max. :83.20
NA's :6
In rarer cases, we will need to group_by() and summarize() our data before statistically analyzing it. This is the case with the cases dataset. Each observation in the cases dataset refers to a combination of things - a province and a country. The issue is that not every country is reporting data at the province level. This means that sometimes the Total.Cases variable is referring to the number of cases in a country and sometimes it is referring to the number of cases in a Province. If we wanted to statistically analyze the number of cases across observations, we first need to transform the dataset so that each observation is reported at the same scale. In other words, we need to zoom out to standardize the observational unit across the dataset to the country level (since we do not always have data at the province level). To do that, we will need to group_by() Country.Region and then summarize the sum of Total.Cases.
#Run this code chunk.
cases %>%
group_by(Country.Region) %>%
summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE)) %>%
ungroup()
Once we’ve done this, we can confidently statistically analyze the Total.Cases variable because we know that the number is always referring to the number of cases in a country.
Alternatively, we could also filter to one country to analyze numeric variables across provinces in that country. If I were to call summary() on the Total.Cases variable in the cases dataset, I would be gathering statistics across numbers reported at different geographic scales. Below, I filter the cases dataset to one Country - Canada - so that I’m gathering statistics across all provinces in Canada.
#Run this code chunk.
cases %>%
filter(Country.Region == "Canada") %>%
select(Total.Cases) %>%
summary()
Total.Cases
Min. : 16
1st Qu.: 906
Median : 12245
Mean : 147491
3rd Qu.: 78285
Max. :1073165
Let’s test the extent to which you will need to zoom in or zoom out to statistically analyze numeric values your data. I’ve selected a numeric variable for each of your datasets. Comment out the line with your dataset and complete the statement below. Think what variables make up the unique key in your datasets. If you have more than one variable in your unique key, make sure that each is represented in your statement below. As a hint, I will note that only one of the six groups has only one variable in their unique key ((ahem infrastructure). Three of the groups have two variables, and two groups (ahem income security) have three variables.
Environment group only: On import your data does require three variables to constitute a unique key. However, with the code below, I’m going to create a new variable in your dataset to uniquely refer to each county so that you do not have reference both the state code and the county code to refer to a county. This variable will be called fips, and it will appear as the last variable in the dataset.
#Environment group only: uncomment this line to create this new variable. Respond to the questions below with this change in the dataset.
#aqi <- aqi %>% mutate(fips = paste(str_pad(as.character(stateCode), 2, side = "left", "0"), str_pad(as.character(countyCode), 3, side = "left", "0"), sep =""))
#Uncomment the line associated with your dataset and fill in the blank. Then run the code.
#paste(df$NUMERIC_VARIABLE[1], "refers to a number/measure of [FILL NUMERIC VARIABLE] in a _____ in my dataset.")
#Example:
paste(hospitals$BEDS[1], "refers to a number of beds in a hospital in my dataset.")
[1] "25 refers to a number of beds in a hospital in my dataset."
paste(world_health_econ$pop[1], "refers to a number of people in a country in a given year in my dataset.")
[1] "18100000 refers to a number of people in a country in a given year in my dataset."
paste(cases$Total.Cases[1], "refers to a number of cases in a country and/or province in my dataset.")
[1] "94226 refers to a number of cases in a country and/or province in my dataset."
#paste(dom_violence_calls$TOTAL_CALLS[1], "refers to a number of calls in a _____ in my dataset.")
#paste(aqi$numberSitesReporting[1], "refers to the number of sites reporting in a _____ in my dataset.")
#paste(internet_master_plan$total_number_of_households[1], "refers to a number of households in a _____ in my dataset.")
paste(ipps$Total.Discharges[1], "refers to a number of discharges in a given hospital based on a diagnosis classification in my dataset.")
[1] "28 refers to a number of discharges in a given hospital based on a diagnosis classification in my dataset."
#paste(snap$certearnavg[1], "refers to a measure of earnings in a _____ in my dataset.")
#paste(self_sufficiency_ca$housingCosts[1], "refers to a measure of housing costs in a _____ in my dataset.")
How did you fill in the last _____?
Is your observational unit one thing (e.g. one hospital, or one country)? If this is the case, it will likely not be as essential for you to zoom in or zoom out before operating on numeric variables. If so, we will say that you do not have qualified units of observation.
OR
Is your observational unit a combination of things or factors (e.g. one chemical reported at a particular facility or one census tract reporting in a particular year)? If this is the case, it will likely be essential for you to zoom in or zoom out before operating on numeric variables. If so, we will say that you do have qualified units of observation.
For each of the groups that has qualified units of observation (most of you do), in some places throughout this lab, you will need to filter your data to particular observations before analyzing across a variable. This is because we will be summarizing information across groups of data, and it will be important to ensure that you are summarizing information across like observations.
Think about what you might filter to in order to ensure that you will be comparing like observations (hint: it will involve a variable in your unique key). Perhaps you will filter to the most recent year, so that you can compare observations across geographies in that year. Or perhaps you will filter to a particular geography, so that you can compare observations across time in that geography. Or perhaps you will filter to a particular diagnosis group, so that you can compare costs across hospitals for that diagnosis. Or perhaps you will filter to a particular year and family type so that you can compare observations across counties in that year for that family type. Characterize one way you might filter your data below. Be specific. Which variable in the dataset will you filter on and to what value(s) will you filter it to?
I will filter my data to the variables DRG.Definition, and I will filter the values to chest pain diagnoses across hospitals.
Zooming in and/or Zooming Out on Your Own Data
Select one of the values that you identified from calling distinct() on a categorical variable in last week’s lab. Filter the dataset to the rows representing that value, select a numeric variable to explore, and then call summary(). If you have qualified units of observation, be sure to first zoom into a set of observations in your data (using filter()).
#Uncomment the appropriate lines below, and fill in your data frame, variables, and value. Run the code.
#_____ %>% filter(_____ == "_____") %>% select(_____) %>% summary()
#ipps %>% filter(DRG.Definition == "313 - CHEST PAIN") %>% select(Total.Discharges) %>% summary()
#If you have qualified units of observation
ipps %>% filter(DRG.Definition == "313 - CHEST PAIN") %>% select(Average.Total.Payments) %>% summary()
Average.Total.Payments
Min. : 3392
1st Qu.: 4326
Median : 4940
Mean : 5431
3rd Qu.: 5994
Max. :14467
#Income security group only
#_____ %>% filter(_____ == _____ & _____ == _____ & _____ == "_____") %>% select(_____) %>% summary()
What question might this analysis help to address?
A question that this analysis might help me to address would be what is the variation in the average total payments for chest pain related diagnosis across hospitals in the US.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? (For instance, for the hospitals dataset we needed to filter to hospitals that were open in order to address questions about infrastructure). Be sure to adjust your code above to reflect this.
No other variables in my dataset need to be considered.
What else would we need to know to fully address this question? Here you may consider what you know about how this dataset was produced and its limitations.
There are limitations to this dataset. For instance, we would need to know exactly what conditions would be classified as "Chest Pain", and it would be helpful to know why this was the primary diagnosis and whether there were other symptoms associated with it as well. Furthermore, it would be helpful to know what tratments are done for this type of diagnosis, and whether each hospital has different criteria when diagnosing chest pain.
What insight can you draw from calling summary() on your filtered dataset?
One insight that I can draw from calling summary() is that there is a significant difference between the minimum and maximum average payments for chest pain disgnosis. This might be due to different treatments performed, lengths of stay of patients, and variation in hospital expenses.
Select a numeric variable in your dataset that represents the extent or scale of the issue you are studying. Pick a number that you believe serves as a good indicator that this issue is at a notable extent or scale, and filter the dataset to all the rows greater than (or less than) this number. Check the remaining distinct values in a categorical variable in the dataset. If you have qualified units of observation, be sure to first zoom into a set of observations in your data (using filter()).
#Uncomment the appropriate lines below, and fill in your data frame, variables, condition, and value. Run the code.
#_____ %>% filter(_____ _____ _____) %>% distinct(_____)
#If you have qualified units of observation
ipps %>% filter(DRG.Definition == "313 - CHEST PAIN" & Total.Discharges > 180) %>% distinct(Provider.Name, Total.Discharges, Provider.City, Provider.State)
#Income security group only
#_____ %>% filter(_____ == _____ & _____ == _____ & _____ _____ _____) %>% distinct(_____)
What question might this analysis help to address?
This analysis might help me address what are the hospitals with the highest number of paients dismissed that had a chest pain diagnosis.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your code above to reflect this.
It would be helpful to know where these hospitals are located and in what US State.
What else would we need to know to fully address this question? Here you may consider what you know about how this dataset was produced and its limitations.
It would be helpful to see how these hospitals classify chest pain diagnosis, and what type of criteria they use.
What insight can you draw from calling distinct on the filtered data?
From calling distinct on my filtered data I can see the name and city of the few hospitals that have more than 180 discharges of patients diagnosed with chest pain, and I can also see that they are located in New York, Texas, and Michigan. This could help me narrow down my research to try explain why these hopsitals have such a high number of chest pain diagnoses, and whether it has to do with the way they classify it.
Select a categorical variable that you would like to group your data by, so that you can summarize some statistics across each grouping. You may group your data by a particular year, by a particular location (such as a state or a region), or by a particular category. Then select a numeric variable in your dataset to summarize by. For instance, you may want to sum the total number of reports in a given year, or find the average number of cases reported in a certain state. Also calculate the percent of observations where data is missing in each group. If you have qualified units of observation, you may want to group the data by one of the variables in your unique key. For instance, if your unique key is a county and year, then perhaps you want to group the data by county and summarize something across each year. If you have qualified units of observation and choose to group by a variable that is not in your unique key, then be sure to filter the data as you have been above.
#Uncomment the appropriate lines below, and fill in your data frame, variables, and summarize variable name, and math function. Then run the code.
ipps %>% group_by(DRG.Definition) %>% summarize(Total.Discharges.DRG = sum(Total.Discharges, na.rm = TRUE), OBSERVATIONS = n(), MISSING = sum(is.na(Total.Discharges)), PERCENT_MISSING = sum(is.na(Total.Discharges))/n()*100)
#If you have qualified units of observation (and not grouping by the qualifier).
#_____ %>% filter(_____ == _____) %>% group_by(_____) %>% summarize(_____ = _____(_____, na.rm = TRUE), OBSERVATIONS = n(), MISSING = sum(is.na(_____)), PERCENT_MISSING = sum(is.na(BEDS))/n()*100)
What question might this analysis help to address?
This analysis could mainly helping me address the question about how many types of classifications diagnoses exist in this dataset, and what the total number of patients diagnosed with each condition is.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
No, there are not.
What else would we need to know to fully address this question? Here you may consider what you know about how this dataset was produced and its limitations.
I would need to acknowledge that there are so many possible variations in classifying diagnoses, and that many of these classifications potentially group together different conditions in one diagnosis. If this dataset were to consider all possible variations and conditions, the number of diasgnoses would much much higher. Also, patients that have been classified with one of these diagnoses might also have other conditions that are not registered, as patients only have a primary diagnosis registered.
What insight can you draw from grouping and summarizing?
I can see what the most common diagnoses are, and how many patients receive that diagnosis. Also, I can see what the rarest diagnoses and procedures are. Also, I can see from the number of observations how many hospitals have at least 1 specific diagnosis. For instance, I can see that there are a total of 28 patients diagnosed with AUTOLOGOUS BONE MARROW TRANSPLANT W/O CC/MCC, but only 2 observations, which means that only 2 hospitals have performed this type of procedure. This could tell me that this type of procedure associated with this diagnosis is pretty rare and might be only performed in a couple of hospitals in the US which might be specialized and equipped to treat such condition.
Combine any combination of the 4 verbs we learned in class this week or last (select, filter, group by, or summarize) to explore your dataset further. You may also use arrange, summary, or distinct.
ipps %>% filter(DRG.Definition == "017 - AUTOLOGOUS BONE MARROW TRANSPLANT W/O CC/MCC") %>% distinct(Provider.Name, Total.Discharges, Provider.City, Provider.State)
NA
What question might this analysis help to address?
What hospitals are specialized have treated AUTOLOGOUS BONE MARROW TRANSPLANT W/O CC/MCC.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
No.
What else would we need to know to fully address this question? Here you may consider what you know about how this dataset was produced and its limitations.
Again, we would need to keep into consideration the fact that these patients might have had other conditions as well, but this was the primary diagnosis and treatment.
What insight can you draw from running this function?
I could potentially deduct that these two hospitals are specialized in treating this condition, although more research should be done to find out more about the type of procedures and treatments available at other hospitals as well.
Variation
Variation is the extent to which the values in a particular variable vary from observation to observation. Examining variation involves looking at the distribution of values in a particular column in the dataset. Do we have a whole bunch of one particular value in a certain variable, and very few of another? Or maybe, do we have a more even distribution of values across a variable?
ggplot
At this point in the assignment, we will begin leveraging the Tidyverse package ggplot to create plots for visualizing the data. To create a plot with ggplot, we will follow this basic formula:
df %>%
ggplot(aes(x = VARIABLE_NAME)) +
CHART_TYPE
For example, for a bar chart, you will call:
df %>%
ggplot(aes(x = VARIABLE_NAME)) +
geom_bar()
For a column chart, you will call:
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col()
Let’s break that down a bit. First, you will call your dataframe. Following your dataframe and a pipe, you will call ggplot(), which basically tells R to prepare to create a plot. Inside ggplot, you will list aesthetics. These are variables in the dataset that you would like to appear on your plot. Setting x = VARIABLE_NAME tells ggplot() what variable to plot on the x-axis. Setting y = VARIABLE_NAME tells ggplot() what variable to plot on the y-axis. Finally, following a plus (+) sign, you tell ggplot which type of plot to create. The ggplot cheatsheet lists a number of plots that you can create with ggplot, as well as a number of different ways to style the plot. We will practice several of these below.
For every plot that you produce, I will expect you to add a title and labels to the x and y axis. You can do this as follows:
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col() +
labs(title = "FILL TITLE", x = "FILL X-AXIS LABEL", y = "FILL Y-AXIS LABEL)
There are also a number of useful tools for styling your plots. For instance we can set the theme of the plot to look a bit more polished by adding “+ theme_bw()” to the plot. I will do this for all plots in this lab.
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col() +
labs(title = "FILL TITLE", x = "FILL X-AXIS LABEL", y = "FILL Y-AXIS LABEL") +
theme_bw()
Two styling issues that I’m sure will come up in most of your plots include: * changing x or y axis tick numbers from scientific to comma notation: + scale_x_continuous(labels = scales::comma) OR + scale_y_continuous(labels = scales::comma) * turning x axis tick marks 90 degrees so that they do not overlap: + theme(axis.text.x = element_text(angle = 90, hjust=1)) OR + theme(axis.text.y = element_text(angle = 90, hjust=1))
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col() +
labs(title = "FILL TITLE", x = "FILL X-AXIS LABEL", y = "FILL Y-AXIS LABEL") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation
So how do we visualize variation with ggplot? Below I describe two different plots that you can leverage to visualize variation - a bar plot and a frequency plot.
Bar Plot
A bar plot displays the number of times each value appears in a categorical variable. This will tell us how the observations in the dataset vary in regards to that variable. In other words, this plot will communicate the number of observations in your dataset by that variable.
#Run this code chunk.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE)) + geom_bar() + labs(title = "TITLE", x = "X-AXIS NAME", y = "Y-AXIS NAME")
hospitals %>%
ggplot(aes(x = TYPE)) +
geom_bar() +
labs(title = "Number of Hospitals in the US by Type", x = "Type", y = "Count of Hospitals") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

Remember that this dataset includes hospitals that are designated as closed. Depending on the question we are trying to address, we may wish to zoom in to only the observations signifying a hospital that is open before creating this plot.
#Run this code chunk.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE)) + geom_bar() + labs(title = "TITLE", x = "X-AXIS NAME", y = "Y-AXIS NAME")
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = TYPE)) +
geom_bar() +
labs(title = "Number of Hospitals in the US that are Open by Type", x = "Type", y = "Count of Hospitals") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

Titling a Bar Plot
Note how I titled my first plot above: “Number of Hospitals in the US by Type” Remember last week, when we identified what makes each observation in our dataset unique? Here I am counting the observations by Type, and in order to know what I’m counting, I need to know what each observation refers to. A good formula for titling bar plots is as follows:
Number of _____ by [x-axis variable name]
In order to fill in the blank line above, consider the statement we produced last week: “I have nrow(df) unique _____ represented in my dataset.” That blank line told us what each observation in the dataset represented - or its observational unit. However we filled in that blank line should also be how we fill in the title of a bar plot.
The [x-axis variable name] should be your x-label and “Count of ______” (filled the same as above) should be your y-label. Note that if you filter your dataset, you should account for this in the title: “Number of Hospitals in the US by Type”
What if I have qualified units of observation?
When we create a bar plot, we are counting the number of observations that fall into each category. If there is only one variable that makes up your unique key, that one variable will represent what is being counted (e.g. above we are counting hospitals by category). However, if there are multiple variables in your unique key, then identifying what it is that you are counting becomes a little more complicated. For instance, let’s say your data reports the population of each country each year as it does in the world_health_econ dataset. Now let’s say that you wanted to plot the number of countries per continent. If you were to call:
#Run this code chunk.
world_health_econ %>%
ggplot(aes(x = continent)) +
geom_bar() +
labs(title = "Number of Countries per Continent - Incorrect", x = "Continent", y = "Count of Countries") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

… you would be counting the combination of the number of countries and years per continent. There are not 800 countries in Africa, but Africa appears in the dataset 800 times because each country in Africa has several rows in the dataset - one for each reporting year. In other words, each country is represented in the bar for every year that it was included in the dataset. The y-axis does not just represent countries but both countries and years. If we want the y-axis to only be counting one thing, then we need to first reduce the dataset to values in a particular context. You can do this by filtering the data as you had been doing above.
#Run this code chunk.
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = continent)) +
geom_bar() +
labs(title = "Number of Countries per Continent in the most Recent Reporting Year", x = "Continent", y = "Count of Countries") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

Note the addition to my title above. If you filter your dataset, the formula for titling changes a bit to Frequency of _____ across [x-axis variable name] in [filtered value]
Select a categorical variable for which you want to visualize the frequency of times it appears in the dataset.
I recommend that you select one of the same categorical variables that you analyzed with the distinct() function last week. If you have qualified units of observation, be sure to filter your data first so that all of the observations you are counting have one variables as a unique key. If you notice styling issues with your data, be sure to consider my notes about how to fix them above.
#Uncomment the line below and fill appropriately. Add a title and labels to your plots, and adjust its style to be legible. Then run the code.
#_____ %>% ggplot(aes(x = _____)) + geom_bar()
#If qualified:
ipps %>% filter(DRG.Definition == "313 - CHEST PAIN") %>% ggplot(aes(x = Provider.State)) + geom_bar() +
labs(title = "Number of Chest Pain Diagnoses across Hospitals by State", x = "State", y = "Count of Chest Pain Diagnoses") +
theme_bw()

Reflect on the distribution of categories in the dataset. Is there an even distribution of observations across each category, or are certain categories more represented than others? Why might this be? What does this say about the social, political, or economic landscape of your topic?
No, there is not an even distribution of observations across States. As it can be seen from the graph there are some States that have a significantly larger number of patients diagnosed and treated for chest pain. One of the reasons why is that some States have higher number of people that are in Medicare.
Reflect on what you learned about the history of the categories you plotted above in last week’s lab. How have the social, political, and economic forces shaping this categorization impacted how we count observations related to this topic? How might this plot look different if this variable had been categorized in a different way?
Fill response here.
Frequency Plot
A frequency plot will display the distribution of values in a numeric variable within a designated set of increments. This will tell us how the observations in the dataset vary in regards to that variable. In other words, this plot will communicate the number of observations in your dataset broken down into increments of the values in that variable.
Consider the plot below. This plot tells us the distribution of beds across open hospitals. It tells us how many hospitals there are in each increment of 10 beds.
#Run this code chunk.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE)) + geom_freqpoly(binwidth = 1) + labs(title = "TITLE", x = "X-AXIS NAME", y = "Y-AXIS NAME")
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS)) +
geom_freqpoly(binwidth = 10) +
labs(title = "Distribution of Beds across Hospitals in the US that are Open", x = "Beds", y = "Count of Hospitals") +
theme_bw()

Note that binwidth refers to the size of the increments at which frequency will be calculated. Above the binwidth is set to 10. This means that ggplot will display the frequency of each value at intervals of 10, 20, 30, 40, etc. When we set the bindwidth to 1, ggplot will display the frequency of each value at intervals of 1, 2, 3, 4. etc. What difference does this make?
Notice what happens when we set the binwidth to 1. While above we count the number of hospitals with 0-10 beds 10-20 beds, 20-30 beds, etc, this will count the number of hospitals with 0-1 beds, 1-2 beds, 2-3 beds, and so on. Because we are counting the number in such small increments, the plot will look much more jagged and will take a longer time to load. This plot displays the counts in finer granularity than the first plot.
#Run this code chunk.
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS)) +
geom_freqpoly(binwidth = 1) +
labs(title = "Distribution of Beds across Hospitals in the US that are Open", x = "Beds", y = "Count of Hospitals") +
theme_bw()

When we set the binwidth to 100, we count the number of hospitals with 0-100 beds, 100-200 beds, 200-300 beds, and so on. Because we are counting the number in larger increments, the plot will look much smoother and will take less time to load. This plot displays the counts in thicker granularity than the first plot.
#Run this code chunk.
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Distribution of Beds across Hospitals in the US that are Open", x = "Beds", y = "Count of Hospitals") +
theme_bw()

Titling a Frequency Plot
Note how I titled my plot above: “Distribution of Beds across Hospitals in the US that are Open” Consider again what makes each observation unique. A good formula for titling frequency plots is as follows:
Frequency of [x-axis variable name] across _____
Again, we can fill in the blank with our observational unit. The [x-axis variable name] should be your x-label and “Count of ______” (filled the same as above) should be your y-label.
What if I have qualified units of observation?
Let’s talk about what would happen if I were to make a frequency plot of the Total.Cases in the cases dataset:
#Run this code chunk.
cases %>%
ggplot(aes(x = Total.Cases)) +
geom_freqpoly(binwidth = 10000) +
labs(title = "Distribution of Cases across ____", x = "Total Cases", y = "Count of _____") + # To add titles and labels
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation

We know that each observation in the cases dataset refers to a province/country pair. So here I’m counting the number of province/countries in each bracket of total cases. Since only some countries in this dataset are broken into provinces, we are comparing counts of cases across different geographic scales - sometimes at the province level and sometimes at the country level. In this case, it makes more sense to total up the number of cases per country and then plot the distribution of cases across countries. We can use group_by() and summarize() to do this:
#Run this code chunk.
cases %>%
group_by(Country.Region) %>%
summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE)) %>%
ungroup() %>%
ggplot(aes(x = Total.Cases)) +
geom_freqpoly(binwidth = 100000) +
labs(title = "Distribution of Cases across Countries", x = "Total Cases", y = "Count of Countries") + # To add titles and labels
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation

What about the world_health_econ data? Without separating out these units of observation, we would be visualizing multiple values reported at the same place at different periods in time (i.e. every year since 1995). Instead, we want to zoom into a single year in the dataset so we are just comparing values across place.
#Run this code chunk.
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = tot_health_sp_pp)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Distribution of Total Health Spending per Person across Countries in 2010", x = "Total Health Spending per Person", y = "Count of Countries") + # To add titles and labels
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation

Note the addition to my title above. If you filter your dataset, the formula for titling changes a bit to Frequency of [x-axis variable name] across _____ in [filtered value]
Select a numeric variable for which you want to visualize the distribution of a set of values.
Be sure to select a variable that describes something about the observational unit and not another categorical variable in your dataset. For instance, let’s say you had the following data table - with each row reporting an environmental violation at a facility:
Violation Number | Facility Name | Facility Town | Population of Facility Town _________________ | _________________ | _________________ | _________________ 1234567 | Facility A | Tarrytown | 90000 2345678 | Facility B | Tarrytown | 90000 3456789 | Facility C | Another Town | 70000
In this table, we would not want to create a frequency plot with population of facility town. This is because our observational unit is a violation, not a town, and population does not describe something about the violation but instead describes something about the town the facility is in. If we were to create a frequency plot with this variable, we would be counting the number of times each population value appears in the dataset - something that does not make much sense, since we can have the same town’s population town appear several times in the dataset if there are more than one violations or more than one facilities in a town. None of you should have to worry about this in your datasets. All of your measures describe the observational unit.
If you have qualified units of observation, be sure to first zoom into a set of observations in your data (using filter()).
#Uncomment the line below and fill appropriately. Add a title and labels to your plots. Run the code.
ipps %>% filter(DRG.Definition == "313 - CHEST PAIN") %>% ggplot(aes(x = Total.Discharges)) + geom_freqpoly(binwidth = 10)

This gives us information about the distribution of values in the dataset. Reflect on the distribution of values. What are the range of values represented in the data? Are the values evenly distributed, or are certain values more represented than others? Why might this be? Do any of the values surprise you? Why?
Fill response here.
Why did you select the binwidth that you did? How might the story your plot tells change if you were to change the binwidth? What anomalies might be hidden with a larger binwidth, and what trends might be hidden with a smaller binwidth?
Fill response here.
Check how the numeric variable was defined in the data dictionary, and quote the definition below. How might the counts represented in your frequency plot appear differently if this variable was defined differently?
Fill response here.
Co-variation
Co-variation is the extent to which the values that constitute two or more variables vary in relation to one another. To visualize co-variation, we might create:
Count Plots
Count plots display how many times two categorical values appear together in a dataset. For instance, in the count plot below, we display the number of open hospitals with each combination of OWNER and TYPE.
#Run this code chunk.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE, y = CATEGORICAL_VARIABLE)) + geom_count()
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = TYPE, y = OWNER)) +
geom_count() +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Number of Hospitals in the US that are Open by Type and Ownership", x = "Type", y = "Ownership")

Titling a Count Plot
Note how I titled my plot above: “Number of Hospitals in the US that are Open by Type and Ownership” Consider again what makes each observation unique. Here I am counting the observations by Type and Ownership, and in order to know what I’m counting, I need to know what each observation refers to. A good formula for titling count plots is as follows:
Number of _____ by [x-axis variable name] and [y-axis variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label and [y-axis variable name] should be your y-label.
What if I have qualified units of observation?
If this is the case I would encourage you to include one of the qualified variables in the x or y-axis. For instance, if the unique key for world_health_econ is country and year, I can include year as the y-axis below to visualize how counts of observations change over time. (Notice how they don’t in the plot below.) Alternatively, if you wish to compare two categorical variables that are not a part of the unique key, be sure to filter the data so that only one variable constitutes the unique key.
#Run this code chunk.
world_health_econ %>%
ggplot(aes(x = continent, y = as.factor(year))) +
geom_count() +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Number of Countries by Continent and Year", x = "Continent", y = "Year")

Stacked Frequency Plots
Stacked frequency plots display the distribution of numeric values in a variable, grouped by a categorical value. For instance, the plot below display the distribution of beds across open hospitals, categorized by the hospital type.
#Run this code chunk.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS, col = TYPE)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Frequency of Beds across Hospitals in the US that are Open by Hospital Type", x = "Beds", y = "Count of Hospital", col = "Type") + # To add titles and labels
theme_bw()

Stacked frequency plots work best when categorizing by a variable with 10 or fewer distinct values. Otherwise, it can be tricky to see the differences in color gradations. If all of your categorical variables have more than 10 distinct values, one thing you might consider is first filtering your data to a few representative categories. For instance, let’s say that I would like to see the distribution of beds in hospitals across states. Since there are 57 states, if I were to categorize the distribution by state, the plot would be very difficult to read.
#Run this code chunk.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS, col = STATE)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Frequency of Beds across Hospitals in the US that are Open by Hospital State", x = "Beds", y = "Count of Hospital", col = "Type") + # To add titles and labels
theme_bw()

In this case, we may wish to first filter our data to a few representative states using %in%.
#Run this code chunk.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
hospitals %>%
filter(STATUS == "OPEN" & STATE %in% (c("CA", "MA", "NY", "FL", "LA"))) %>%
ggplot(aes(x = BEDS, col = STATE)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Frequency of Beds across Hospitals in the US that are Open by Hospital State", x = "Beds", y = "Count of Hospital", col = "Type") + # To add titles and labels
theme_bw()

Titling a Stacked Frequency Plot
Note how I titled my plot above: “Frequency of Beds across Hospitals in the US that are Open by Hospital Type” Consider again what makes each observation unique. Here I am counting the observations by number of Beds and Hospital Type. A good formula for titling stacked frequency plots is as follows:
Frequency of [x-axis variable name] across _____ by [col variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label, “Count of ______” (filled the same as above) should be your y-label, and the [col variable name] should be your col-label.
What if I have qualified units of observation?
If this is the case I would encourage you to include one of the qualified variables in the col variable. For instance, if world_health_econ is qualified by country and year, I can include year as the col variable below to visualize how the frequency of countries with various life expectancies changes over time.
#Run this code chunk.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
world_health_econ %>%
ggplot(aes(x = life_exp, col = as.factor(year))) +
geom_freqpoly(binwidth = 5) +
theme_bw() +
labs(title = "Frequency of Life Expectancies across Countries by Year", x = "Life Expectancy", y = "Count of Countries", col = "Life Expectancy")

Note that this is one plot that is particularly susceptible to missing data. If certain countries did not report data in certain years, the count of countries in a bracket will appear lower, not necessarily because fewer countries fell within a certain life expectancy bracket, but because fewer countries reported that life expectancy.
Alternatively, you could zoom in to one value in one of your qualified variables, filtering to a specific subset of observations and then divide by a different categorical variable.
#Run this code chunk.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = life_exp, col = continent)) +
geom_freqpoly(binwidth = 5) +
theme_bw() +
labs(title = "Frequency of Life Expectancies across Countries by Continent in 2010", x = "Life Expectancy", y = "Count of Countries", col = "Continent")

Point plots
Point plots display the relationship between a categorical variable and a numeric variable. For instance, the plot below displays a relationship between hospital type and the number of beds at the hospital. Notably, unlike the plots we have been viewing until now, with point plots, we see a point for every observation in the dataset. Because point plots display every observation (rather than aggregating them into other polygons and lines), they are particularly good for seeing outliers in the data. However, with large datasets, this also can mean that points will overlap. Note that the first plot below exhibits overplotting - when the data represented on a plot overlaps, making it difficult to discern one point from the next. There are various tools available to deal with over-plotting. You can reduce the size of points on the plot, increase their transparency, or set them to slightly offset each other (known as adding jitter). We do all three in the second plot below.
#Run this code chunk.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE, y = NUMERIC_VARIABLE)) + geom_point()
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = TYPE, y = BEDS)) +
geom_point() +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Number of Beds in Hospitals by Type", x = "Type", y = "Number of Beds")

hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = TYPE, y = BEDS)) +
geom_jitter(size = 0.5, alpha = 0.1) + #Change geom_point to geom_jitter, reduce the size, add transparency for overplotting
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Number of Beds in Hospitals by Type", x = "Type", y = "Number of Beds")

Notice that think black line in the column for Critical Access hospitals. Based on what we’ve learned of critical access hospitals, can you surmise what number they are clustered at?
(+.25 points on lab if you can respond correctly here.)
Critical access hospitals have many guidelines they have to follow in order to receive funding. In this case, the black line in the column represents the cluster of beds at the value 25. That is because critical access hospitals can't have more than 25 beds in order to adhere to guidelines and receive funding.
Titling a Point Plot
Note how I titled my plot above: “Number of Beds in Hospitals in the US that are Open by Type” Here I am displaying the number of beds by Type. A good formula for titling point plots is as follows:
Number/Measure of [y-axis variable name] in _____ by [x-axis variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label and “Number/Measure of [y-axis variable name]” should be your y-label.
What if I have qualified units of observation?
If this is the case I would encourage you to filter your data as you have been doing elsewhere. For instance if world_health_econ is qualified by country and year, I can filter to the most recent year before creating a point plot of the private share of health spending by continent.
#Run this code chunk.
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = continent, y = priv_share_health_sp)) +
geom_point(size = 2, alpha = 0.8) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Private Share of Health Spending in Countries by Continent in 2010", x = "Continent", y = "Private Share of Health Spending")

Scatterplots
Scatterplots display the relationship or correlation between two numeric variables. For instance, below we plot the relationship between the BEDS variable and the POPULATION variable in the hospitals dataset.
There are different ways to characterize the correlations between variables in data. We may consider the strength of a correlation, the shape of a correlation, and whether the correlation is positive or negative.
- Two variables in a scatterplot can be said to have a strong correlation when points are clustered closely to a central line or curve. The more scattered throughout the plot the points are, the weaker the correlation.
- Two variables in a scatterplot can be said to have a linear correlation when the scatterplot tends to produce a straight line. This means that the rate of change between two variables is steady. However, when a scatterplot produces a curve, this indicates that the rate of change between two variables is not as constant.
- Two variables in a scatterplot can be said to have a positive correlation when the points move upward from the bottom left corner towards the top right corner of the plot. This means that as values in variable increases, the values in the other variable also increase. When points move downward from the top left corner to the bottom right corner of the plot, we can say that the variables negatively correlation. This means that as values in variable increases, the values in the other variable decreases.
#Run this code chunk.
#ggplot(df, aes(x = NUMERIC_VARIABLE, y = NUMERIC_VARIABLE)) + geom_point()
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS, y = POPULATION)) +
geom_point(size = 0.5) +
theme_bw() +
labs(title = "Relationship between Hospital Beds and Population in the US", x = "Beds", y = "Population")

Note that this plot has a strong, linear positive correlation. As BEDS increase in this variable, POPULATION also tends to increase.
Titling a Scatterplot
Note how I titled my plot above: “Relationship between Hospital Beds and Population in the US” A good formula for titling scatterplots is as follows:
Relationship between _____ [x-axis variable name] and [y-axis variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label and [y-axis variable name]" should be your y-label.
What if I have qualified units of observation?
If this is the case I would encourage you to filter your plot to one value in one of your qualified variables. For instance if world_health_econ is qualified by country and year, I can filter to the most recent year before creating a point plot of the private share of health spending by continent.
#Run this code chunk.
#ggplot(df, aes(x = NUMERIC_VARIABLE, y = NUMERIC_VARIABLE)) + geom_point()
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = tot_health_sp_pp, y = life_exp, size = pop, col = continent)) +
geom_point(shape = 21, stroke = 1) +
labs(title = "Relationship between Country Total Health Spending Per Person and Life Expectancy", x = "Total Health Spending Per Person", y = "Life Expectancy", size = "Population", col = "Continent") +
theme_bw() +
scale_size_continuous(range = c(1, 10), labels = scales::comma)

Note that this plot has a weaker, curvilinear, positive correlation. As Total Health Spending per Person increases in this variable, Life Expectancy also tends to increase, but the rate of change at which it increases is not constant.
Have you heard the quip “Correlation does not equal causation”? This is particularly important to consider here. In lab 7, we will examine some confounding variables that may be mediating how values appear to correlate in our data. For now, it’s important to note that just because we see a correlation between total health spending and life expectancy does not mean that increasing total health spending in a country causes life expectancy to increase. This is of course a complex issue with lots of other variables involved.
Produce two plots that represent co-variation in your dataset.
You need not include every plot I described above. Be sure to zoom in or out on your data if you have qualified units of observation.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
ipps %>%
filter(DRG.Definition %in% (c("313 - Chest Pain", "813 - COAGULATION DISORDERS", "312 - SYNCOPE & COLLAPSE", "652 - KIDNEY TRANSPLANT", "069 - TRANSIENT ISCHEMIA"))) %>%
ggplot(aes(x = Average.Total.Payments, col = DRG.Definition)) +
geom_freqpoly(binwidth = 20000) +
labs(title = "Frequency of Average Total Payments across Hospitals by Diagnosis", x = "Average Total Payments", y = "Count of Hospitals Diagnoses", col = "Diagnosis Type") +
theme_bw()

What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What else would we need to know to fully address this question? Here you may consider what you know about how this dataset was produced and its limitations.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
#Fill the code for plot 2 here. Add a title and labels to your plots. Be sure to adjust for overplotting.
ipps %>%
filter(DRG.Definition %in% (c("313 - Chest Pain", "813 - COAGULATION DISORDERS", "312 - SYNCOPE & COLLAPSE", "652 - KIDNEY TRANSPLANT", "069 - TRANSIENT ISCHEMIA", "038 - EXTRACRANIAL PROCEDURES W CC", "472 - CERVICAL SPINAL FUSION W CC", "551 - MEDICAL BACK PROBLEMS W MCC", "637 - DIABETES W MCC"))) %>%
ggplot(aes(x = DRG.Definition , y = Average.Total.Payments)) +
geom_jitter(size = 0.5, alpha = 0.1) + #Change geom_point to geom_jitter, reduce the size, add transparency for overplotting
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Average Total Payments across Hospitals by Diagnosis", x = "Diagnosis Type", y = "Average Total Payments")

NA
NA
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What else would we need to know to fully address this question? Here you may consider what you know about how this dataset was produced and its limitations.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
LS0tCnRpdGxlOiAiTGFiIDUgLSBEYXRhIFZhcmlhdGlvbiBhbmQgQ28tVmFyaWF0aW9uIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzMnCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIyBJbnN0cnVjdGlvbnMgYW5kIE92ZXJ2aWV3CgpJbiB0aGlzIGFzc2lnbm1lbnQsIHdlIHdpbGwgcHJhY3RpY2UgZ3JhcGhpY2FsbHkgcmVwcmVzZW50aW5nIHZhcmlhdGlvbiBhbmQgY292YXJpYXRpb24gaW4gYSBkYXRhc2V0LiBUbyBiZWdpbiB5b3Ugd2lsbCBuZWVkIHRvIGltcG9ydCBhbmQgY2xlYW4geW91ciBkYXRhc2V0LiBZb3UgbWF5IHJlZmVyZW5jZSBsYXN0IHdlZWsncyBsYWIgdG8gaGVscCB3aXRoIHRoaXMuIEFmdGVyIHRoaXMsIHlvdSBzaG91bGQgZm9sbG93IHRoZSBwcm9tcHRzIGFuZCBjb21wbGV0ZSB0aGUgc2hvcnQgYW5zd2VyIHF1ZXN0aW9ucy4gQXQgdmFyaW91cyBwb2ludHMgaW4gdGhpcyBhc3NpZ25tZW50LCB5b3Ugd2lsbCBiZSBhc2tlZCB0byBkcmF3IGluc2lnaHRzIGFib3V0IHlvdXIgZGF0YXNldCBhZnRlciBjYWxsaW5nIGNlcnRhaW4gZnVuY3Rpb25zLiBXaGVuIEkgYXNrIHlvdSB0byBkcmF3IGFuIGluc2lnaHQsIEnigJltIG5vdCBhc2tpbmcgeW91IHRvIGRlc2NyaWJlIHdoYXQgdGhlIGZ1bmN0aW9uIGRvZXMgb3IgdG8gc3RhdGUgdGhlIHJlc3VsdHMgdGhhdCB5b3UgZ2V0LiBJbnN0ZWFkIEnigJltIGFza2luZyB5b3UgdG8gaW50ZXJwcmV0IHRob3NlIHJlc3VsdHMgYW5kIGNvbnNpZGVyIHdoYXQgdGhpcyBtaWdodCB0ZWxsIHVzIGFib3V0IHRoZSBpc3N1ZXMgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGFzZXQgb3IgaWYgaXQgbWlnaHQgc2lnbmFsIGlzc3VlcyBvZiBkYXRhIHF1YWxpdHkuIEZvciBpbnN0YW5jZSwgc3RhdGluZyAidGhlIG1heGltdW0gdmFsdWUgaW4gdGhlIGFnZSBjb2x1bW4gaXMgOTk5LCIgaXMgbm90IGFuIGluc2lnaHQuIEluc3RlYWQgeW91IHNob3VsZCBzYXksICJ0aGUgbWF4aW11bSB2YWx1ZSBpbiB0aGUgYWdlIGNvbHVtbiBpcyA5OTksIHdoaWNoIGlzIG11Y2ggaGlnaGVyIHRoYW4gSSB3b3VsZCBleHBlY3QgYW5kIG1heSBzaWduYWwgdGhhdCB0aGUgZGF0YSB3YXMgaW5wdXQgd3Jvbmcgb3IgdGhhdCB0aGUgZGF0YSBjb2xsZWN0b3JzIGF0IHVzaW5nIDk5OSB0byByZXByZXNlbnQgbnVsbCB2YWx1ZXMuIgoKIyMgR2V0dGluZyBTdGFydGVkCgojIyMgTG9hZCB0aGUgcmVsZXZhbnQgbGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHNoaW55KQpsaWJyYXJ5KHNoaW55ZGFzaGJvYXJkKQpgYGAKCiMjIyBJbXBvcnQgYW5kIGNsZWFuIGV4YW1wbGUgZGF0YXNldHMgCgpgYGB7cn0KaG9zcGl0YWxzIDwtIHJlYWQuY3N2KCIvVXNlcnMvbHBvaXJpZXIvRG9jdW1lbnRzL0dpdEh1Yi9TVFMtMTE1L2RhdGFzZXRzL0hvc3BpdGFscy5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgp3b3JsZF9oZWFsdGhfZWNvbiA8LSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2xpbmRzYXlwb2lyaWVyL1NUUy0xMTUvbWFzdGVyL2RhdGFzZXRzL3dvcmxkX2hlYWx0aF9lY29uLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmNhc2VzIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkvbWFzdGVyL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzL3RpbWVfc2VyaWVzX2NvdmlkMTlfY29uZmlybWVkX2dsb2JhbC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojRG8gbm90IHdvcnJ5IGFib3V0IHRoaXMgbGluZSBvZiBjb2RlIGZvciBub3cuIFNpbmNlIHRoZSBjYXNlcyBkYXRhIGdldHMgYXBwZW5kZWQgZXZlcnkgZGF5IHdpdGggYSBuZXcgY29sdW1uIHJlcHJlc2VudGluZyB0aGF0IGRheSdzIGNhc2UgY291bnRzLCBpZiB3ZSB3YW50IHRoZSB0b3RhbCBjYXNlcyBwZXIgY291bnRyeSwgd2UgbmVlZCB0byBhZGQgdXAgYWxsIG9mIHRoZSBwcmV2aW91cyBkYXkncyBjb3VudHMgaW50byBhIG5ldyBjb2x1bW4uIFRoZSBjb2x1bW4gYmVsb3cgZG9lcyB0aGlzIGZvciB1cy4gCmNhc2VzIDwtIAogIGNhc2VzICU+JSAKICBtdXRhdGUoVG90YWwuQ2FzZXMgPSAKICAgICAgICAgICBjYXNlcyAlPiUgCiAgICAgICAgICAgc2VsZWN0KHN0YXJ0c193aXRoKCJYIikpICU+JSAKICAgICAgICAgICByb3dTdW1zKCkKICAgICAgICAgKSAlPiUKICBzZWxlY3QoUHJvdmluY2UuU3RhdGUsIENvdW50cnkuUmVnaW9uLCBUb3RhbC5DYXNlcykKCmhvc3BpdGFscyRaSVAgPC0gYXMuY2hhcmFjdGVyKGhvc3BpdGFscyRaSVApCgpob3NwaXRhbHMkWklQIDwtIHN0cl9wYWQoaG9zcGl0YWxzJFpJUCwgNSwgcGFkID0gIjAiKSAKCmlzLm5hKGhvc3BpdGFscykgPC0gaG9zcGl0YWxzID09ICJOT1QgQVZBSUxBQkxFIgppcy5uYShob3NwaXRhbHMpIDwtIGhvc3BpdGFscyA9PSAtOTk5CmlzLm5hKGNhc2VzKSA8LSBjYXNlcyA9PSAiIgoKaG9zcGl0YWxzJFNPVVJDRURBVEUgPC0geW1kX2htcyhob3NwaXRhbHMkU09VUkNFREFURSkKaG9zcGl0YWxzJFZBTF9EQVRFIDwtIHltZF9obXMoaG9zcGl0YWxzJFZBTF9EQVRFKQpgYGAKCiMjIyBJbXBvcnQgYW5kIGNsZWFuIHlvdXIgZGF0YXNldC4gCgpgYGB7cn0KI1VuY29tbWVudCB0aGUgbGluZXMgYXNzb2NpYXRlZCB3aXRoIHlvdXIgZGF0YXNldHMgYmVsb3cgYW5kIHRoZW4gcnVuIHRoZSBjb2RlIGNodW5rLgoKI2RvbV92aW9sZW5jZV9jYWxscyA8LSByZWFkLmNzdigiaHR0cHM6Ly9kYXRhLW9wZW5qdXN0aWNlLmRvai5jYS5nb3Yvc2l0ZXMvZGVmYXVsdC9maWxlcy9kYXRhc2V0LzIwMTktMDYvRFZSQ0FfMjAwMS0yMDE4LmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKI2RvbV92aW9sZW5jZV9jYWxscyA8LSBkb21fdmlvbGVuY2VfY2FsbHMgJT4lIHVuaXRlKCJZRUFSX01PTlRIIiwgWUVBUiwgTU9OVEgsIHNlcCA9ICItIiwgcmVtb3ZlID0gVFJVRSkgJT4lIG11dGF0ZShZRUFSX01PTlRIID0geW1kKFlFQVJfTU9OVEgsIHRydW5jYXRlZCA9IDEpKQoKI2ludGVybmV0X21hc3Rlcl9wbGFuIDwtIHJlYWQuY3N2KCJodHRwczovL2RhdGEuY2l0eW9mbmV3eW9yay51cy9yZXNvdXJjZS9mZzVqLXE1bmsuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQojaXMubmEoaW50ZXJuZXRfbWFzdGVyX3BsYW4pIDwtIGludGVybmV0X21hc3Rlcl9wbGFuID09ICJOL0EiCgppcHBzIDwtIHJlYWQuY3N2KCJodHRwczovL2RhdGEuY21zLmdvdi9hcGkvdmlld3MvdGNzcC02ZTk5L3Jvd3MuY3N2PyRsaW1pdD0yMDAwMDAiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojc25hcCA8LSByZWFkLmNzdigiaHR0cHM6Ly9naXRodWIuY29tL2xpbmRzYXlwb2lyaWVyL1NUUy0xMTUvYmxvYi9tYXN0ZXIvZGF0YXNldHMvU05BUF9Qb2xpY3lfRGF0YWJhc2UuY3N2P3Jhdz10cnVlIiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQojaXMubmEoc25hcCkgPC0gc25hcCA9PSAtOSAKI3NuYXAkeWVhcm1vbnRoIDwtIHltZChzbmFwJHllYXJtb250aCwgdHJ1bmNhdGVkID0gMSkgIAoKI3NlbGZfc3VmZmljaWVuY3lfY2EgPC0gcmVhZC5jc3YoImh0dHBzOi8vZ2l0aHViLmNvbS9saW5kc2F5cG9pcmllci9TVFMtMTE1L2Jsb2IvbWFzdGVyL2RhdGFzZXRzL0NBMjAyMF8yMDE4X1NTUy5jc3Y/cmF3PXRydWUiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiNzZWxmX3N1ZmZpY2llbmN5X2NhWzExOjI0XSA8LSBsYXBwbHkoc2VsZl9zdWZmaWNpZW5jeV9jYVsxMToyNF0sIGdzdWIsIHBhdHRlcm4gPSAiW1xcJCwlKCkgXSIsIHJlcGxhY2VtZW50ID0gIiIpCiNzZWxmX3N1ZmZpY2llbmN5X2NhWzExOjI0XSA8LSBsYXBwbHkoc2VsZl9zdWZmaWNpZW5jeV9jYVsxMToyNF0sIGFzLm51bWVyaWMpCgojYXFpIDwtIHJlYWQuY3N2KCJodHRwczovL2dpdGh1Yi5jb20vbGluZHNheXBvaXJpZXIvU1RTLTExNS9ibG9iL21hc3Rlci9kYXRhc2V0cy9kYWlseV9hcWlfYnlfY291bnR5XzIwMTkuY3N2P3Jhdz10cnVlIiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQojYXFpJGRhdGUgPC0gbWR5KGFxaSRkYXRlKSAKYGBgCgojIyBFeHBsb3JpbmcgU3Vic2V0dGVkIG9yIEdyb3VwZWQgRGF0YQoKTGFzdCB3ZWVrLCB3ZSBleHBsb3JlZCBob3cgeW91ciBkYXRhIHdhcyBkZWZpbmVkLCBob3cgaXQgd2FzIGNhdGVnb3JpemVkLCBhbmQgaG93IG1pc3NpbmcgdmFsdWVzIHdlcmUgcmVwcmVzZW50ZWQuIFRocm91Z2ggdGhpcyBleGVyY2lzZSwgd2Ugd2VyZSBhYmxlIHRvIGRldmVsb3AgYSBnZW5lcmFsIG92ZXJ2aWV3IG9mIHRoZSBvYnNlcnZhdGlvbnMsIHZhcmlhYmxlcywgYW5kIHZhbHVlcyBpbiBvdXIgZGF0YXNldHMuIEtub3dpbmcgdGhpcyB3ZSBsaWtlbHkgaGF2ZSBhIGJldHRlciBzZW5zZSBvZiBhcmVhcyB3ZSB3YW50IHRvIGJlIGFibGUgdG8gem9vbSBpbnRvIGFuZCBleHBsb3JlIGluIG91ciBkYXRhLiBXZSBhbHNvIHNvbWV0aW1lcyB3YW50IHRvIGJlIGFibGUgdG8gem9vbSBvdXQgLSBzdW1tYXJpemluZyBzb21ldGhpbmcgYWNyb3NzIGdyb3VwcyBvZiBvYnNlcnZhdGlvbnMgaW4gb3VyIGRhdGEuICBBcyB3ZSBwcmVwYXJlIHRvIHZpc3VhbGl6ZSB2YXJpYXRpb24gYW5kIGNvLXZhcmlhdGlvbiBpbiB0aGUgZGF0YXNldCwgbGV0J3MgZmlyc3QgZ28gb3ZlciBob3cgd2UgY2FuIGJvdGggem9vbSBpbiBhbmQgem9vbSBvdXQgb24gb3VyIGRhdGFzZXRzLiAKCiMjIyBab29taW5nIGluIC0gRXhwbG9yaW5nIEZpbHRlcmVkIENhdGVnb3JpY2FsIERhdGEKCiMjIyMgRmlsdGVyaW5nIHRvIGEgQ2F0ZWdvcnkKCkZpbHRlcmluZyBpcyBvbmUgd2F5IHdlIGNhbiB6b29tIGluIG9uIG91ciBkYXRhIC0gZXhwbG9yaW5nIG9ubHkgdGhvc2Ugb2JzZXJ2YXRpb25zIHRoYXQgbWVldCBhIHBhcnRpY3VsYXIgY3JpdGVyaWEuCgpGb3IgaW5zdGFuY2UsIGxhc3Qgd2VlayB3ZSBsZWFybmVkIGFib3ZlIHRoYXQgb25lIGNyaXRlcmlhIGZvciBiZWluZyBkZXNpZ25hdGVkIGFzIGEgQ3JpdGljYWwgQWNjZXNzIEhvc3BpdGFsIGlzIHRoYXQgdGhlIGhvc3BpdGFsIG11c3QgaGF2ZSAyNSBvciBmZXdlciBpbnBhdGllbnQgYmVkcy4gV2UgbWF5IHdhbnQgdG8gc2VlIGhvdyB0aGUgdmFsdWVzIGZvciBCRURTIGNoYW5nZSB3aGVuIHdlIGZpbHRlciB0byAob3Igem9vbSBpbnRvKSBqdXN0IHRob3NlIG9ic2VydmF0aW9ucyByZXByZXNlbnRpbmcgY3JpdGljYWwgYWNjZXNzIGhvc3BpdGFscy4gTm90aWNlIGhvdyB3ZSBjYW4gY29tYmluZSBhbnkgbnVtYmVyIG9mIGRwbHlyIHZlcmJzIHVzaW5nIHRoZSBwaXBlICglPiUpLiBCZWxvdyBJIHdpbGwgZmlsdGVyIHRvIHJvd3MgdGhhdCBtZWV0IGEgY3JpdGVyaWEgYW5kIHRoZW4gc2VsZWN0IGEgdmFyaWFibGUgdG8gZXhhbWluZSBmcm9tIHRoZSBmaWx0ZXJlZCBkYXRhLgoKYGBge3J9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKI2RmICU+JSBmaWx0ZXIoQ0FURUdPUklDQUxfVkFSSUFCTEUgPT0gIlZBTFVFIikgJT4lIHNlbGVjdChDQVRFR09SSUNBTF9WQVJJQUJMRSkKaG9zcGl0YWxzICU+JSBmaWx0ZXIoVFlQRSA9PSAiQ1JJVElDQUwgQUNDRVNTIikgJT4lIHNlbGVjdChOQU1FLCBCRURTKQpob3NwaXRhbHMgJT4lIGZpbHRlcihUWVBFID09ICJDUklUSUNBTCBBQ0NFU1MiKSAlPiUgc2VsZWN0KEJFRFMpICU+JSBzdW1tYXJ5KCkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIHNvbWUgaG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGhhdmUgYmVlbiBkZXNpZ25hdGVkIGFzIGNyaXRpY2FsIGFjY2VzcyBob3NwaXRhbHMgdGhhdCBoYXZlIG1vcmUgdGhhbiAyNSBiZWRzLiBTaW5jZSB0aGlzIGRvZXMgbm90IGFsaWduIHdpdGggdGhlIGNyaXRlcmlhIGZvciBjcml0aWNhbCBhY2Nlc3MgaG9zcGl0YWxzIHRoYXQgd2UgZGlzY292ZXJlZCBpbiBvdXIgcmVzZWFyY2gsIGl0IGlzIGxpa2VseSBzb21ldGhpbmcgdGhhdCB3ZSB3aWxsIHdhbnQgdG8gaW52ZXN0aWdhdGUgZnVydGhlci4KCiMjIyMgRmlsdGVyaW5nIHRvIE51bWVyaWMgT2JzZXJ2YXRpb25zIEFib3ZlIG9yIEJlbG93IGEgVGhyZXNob2xkCgpXZSBtYXkgYWxzbyB3YW50IHRvIHNlZSB3aGljaCBzdGF0ZXMgaGF2ZSBob3NwaXRhbHMgd2l0aCBtb3JlIHRoYW4gMTIwMCBiZWRzLiBUbyBkbyBzbywgd2Ugd291bGQgZmlsdGVyIHRoZSBkYXRhIHRvIHRob3NlIG9ic2VydmF0aW9ucyB3aGVyZSBCRURTIGlzIGdyZWF0ZXIgdGhhbiAxMjAwLiBUaGUgZmlyc3QgdGltZSBJIGRvIHRoaXMgYmVsb3csIEkgc2VsZWN0KCkgdGhlIE5BTUUgb2YgdGhlIGhvc3BpdGFsIGFuZCB0aGUgU1RBVEUuIFRoaXMgc2hvd3MgZXZlcnkgaG9zcGl0YWwgd2l0aCBtb3JlIHRoYW4gMTIwMCBiZWRzLCBhbG9uZyB3aXRoIHRoZSBTVEFURSBpbiB3aGljaCBpdCBpcyBsb2NhdGVkLiBIb3dldmVyLCB3aGF0IGlmIEkgb25seSB3YW50ZWQgdG8ga25vdyB3aGljaCBzdGF0ZXMgaGFkIGhvc3BpdGFscyB3aXRoIG1vcmUgdGhhbiAxMjAwIGJlZHM/IEkgd291bGRuJ3QgbmVjZXNzYXJpbHkgd2FudCB0byBzZWxlY3QoKSBTVEFURSBpbiB0aGlzIGNhc2UgYmVjYXVzZSB0aGlzIHdvdWxkIHNob3cgbWUgdGhlIHN0YXRlIGZvciBldmVyeSBvYnNlcnZhdGlvbiBpbiBteSBmaWx0ZXJlZCBkYXRhLiBBcyB5b3UgY2FuIHNlZSBiZWxvdywgdGhpcyBtZWFucyB0aGF0IENBIHdvdWxkIGFwcGVhciA3IHRpbWVzISBJbnN0ZWFkLCBJIHdvdWxkIHdhbnQgdG8gY2hlY2sgdGhlIGRpc3RpbmN0KCkgU1RBVEVTIGluIHRoZSBmaWx0ZXJlZCBkYXRhLiBDaGVjayBvdXQgaG93IEkgZG8gdGhpcyBiZWxvdy4gCgpgYGB7cn0KI1J1biB0aGlzIGNvZGUgY2h1bmsuCgojZGYgJT4lIGZpbHRlcihOVU1CRVJJQ19WQVJJQUJMRSA+IFZBTFVFKSAlPiUgZGlzdGluY3QoQ0FURUdPUklDQUxfVkFSSUFCTEUpCgojTGlzdHMgbmFtZSBhbmQgc3RhdGUgb2YgaG9zcGl0YWxzIHdpdGggbW9yZSB0aGFuIDEyMDAgYmVkcy4KaG9zcGl0YWxzICU+JSBmaWx0ZXIoQkVEUyA+IDEyMDApICU+JSBzZWxlY3QoTkFNRSwgU1RBVEUpIAoKI0xpc3RzIHN0YXRlIGZvciBldmVyeSBob3NwaXRhbCB3aXRoIG1vcmUgdGhhbiAxMjAwIGJlZHMgaW4gdGhlIGRhdGFzZXQKaG9zcGl0YWxzICU+JSBmaWx0ZXIoQkVEUyA+IDEyMDApICU+JSBzZWxlY3QoU1RBVEUpIAoKI0xpc3RzIHRoZSBzdGF0ZXMgd3RpaCBtb3JlIHRoYW4gMTIwMCBiZWRzCmhvc3BpdGFscyAlPiUgZmlsdGVyKEJFRFMgPiAxMjAwKSAlPiUgZGlzdGluY3QoU1RBVEUpIApgYGAKCiMjIyBab29taW5nIG91dCAtIGFrYSBncm91cGluZyBjb21tb24gdmFsdWVzIGFuZCBzdW1tYXJpemluZwoKQXQgdGltZXMsIHdlIGFyZSBzZWVraW5nIHRvIGdldCBhIGJyb2FkZXIgcGljdHVyZSBvZiB3aGF0J3MgZ29pbmcgb24gaW4gb3VyIGRhdGFzZXQgdGhhbiBwcm92aWRlZCAtIGdyb3VwaW5nIG9ic2VydmF0aW9ucyB0aGF0IHNoYXJlIGEgY29tbW9uIHZhbHVlIGFuZCB0aGVuIHBlcmZvcm1pbmcgYSBjYWxjdWxhdGlvbiB0byBzdW1tYXJpemUgc29tZXRoaW5nIHdpdGhpbiBlYWNoIG9mIHRob3NlIGdyb3Vwcy4gSW4gb3RoZXIgd29yZHMsIHNvbWV0aW1lcyB3ZSB3YW50IHRvIHNlZSBvdXIgZGF0YSBpbiBhZ2dyZWdhdGUuIEZvciBpbnN0YW5jZSwgSSBtYXkgd2FudCB0byBrbm93IHRoZSB0b3RhbCBudW1iZXIgb2YgaG9zcGl0YWwgYmVkcyBwZXIgc3RhdGUuIFRvIGNhbGN1bGF0ZSB0aGlzLCBJIHdvdWxkIG5lZWQgdG8gZ3JvdXAgYWxsIG9mIHRoZSBob3NwaXRhbCBvYnNlcnZhdGlvbnMgYnkgc3RhdGUgYW5kIHRoZW4gc3VtIHRoZSB0b3RhbCBudW1iZXIgb2YgYmVkcyBpbiBlYWNoIGdyb3VwLiAKSW4gc3VjaCBjYXNlcywgd2UgY2FuIGNhbGwgKipncm91cF9ieSgpKiogdG8gYWdncmVnYXRlIHRoZSBvYnNlcnZhdGlvbnMgd2l0aCBjb21tb24gdmFyaWFibGUgdmFsdWVzIGludG8gZ3JvdXBzLiBUaGVuIHdlIHdpbGwgY2FsbCAqKnN1bW1hcml6ZSgpKiogdG8gcGVyZm9ybSBhIGNhbGN1bGF0aW9uIHdpdGhpbiBlYWNoIG9mIHRob3NlIGdyb3Vwcy4gKipzdW1tYXJpemUoKSoqIHRha2VzIGEgc2V0IG9mIHZhbHVlcyBhbmQgYSBjYWxjdWxhdGlvbiBtZXRob2QgYW5kIHJldHVybnMgYSBzaW5nbGUgdmFsdWUuIEZvciBpbnN0YW5jZSwgaWYgd2UgY2FsbCBzdW1tYXJpemUoKSB3aXRoIGEgbnVtZXJpYyBjb2x1bW4gaW4gb3VyIGRhdGFzZXQgYW5kICJtZWFuIiBhcyBhIGNhbGN1bGF0aW9uIG1ldGhvZCwgaXQgd2lsbCByZXR1cm4gdGhlIGF2ZXJhZ2Ugb2YgYWxsIHRoZSBudW1lcmljIHZhbHVlcyBpbiB0aGF0IGNvbHVtbi4gV2hlbiBjYWxsZWQgaW4gY29uanVuY3Rpb24gd2l0aCBncm91cF9ieSgpLCAqKnN1bW1hcml6ZSgpKiogdGFrZXMgYSBzZXQgb2YgdmFsdWVzIGZvciBlYWNoIGdyb3VwIGFuZCBhIGNhbGN1bGF0aW9uIG1ldGhvZCBhbmQgcmV0dXJucyBhIHNpbmdsZSB2YWx1ZSBmb3IgZWFjaCBncm91cC4gCgpGb3IgdGhlIGhvc3BpdGFscyBkYXRhc2V0LCB3ZSB3aWxsIGdyb3VwIHRoZSBvYnNlcnZhdGlvbnMgYnkgU1RBVEUgYW5kIHRoZW4gdXNlIHN1bW1hcml6ZSB0byBjYWxjdWxhdGUgdGhlIHN1bSBvZiBCRURTIHBlciBzdGF0ZS4gTm90aWNlIGJlbG93IGhvdyB3ZSBhcmUgY2hvb3NpbmcgdG8gaWdub3JlIE5BIHZhbHVlcyBhYm92ZSBieSBjYWxsaW5nIG5hLnJtID0gVFJVRS4gV2hlbiB3ZSBkbyBzbywgd2UgbmVlZCB0byBrZWVwIGluIG1pbmQgdGhhdCB3ZSBhcmUgbm90IHN1bW1hcml6aW5nIGFjcm9zcyBhbGwgb2JzZXJ2YXRpb25zIGluIHRoZSBkYXRhc2V0LCBidXQgb25seSB0aG9zZSBmb3Igd2hpY2ggdGhlcmUgaXMgYSB2YWx1ZSBsaXN0ZWQgaW4gdGhlIHZhcmlhYmxlIHdlIGFyZSBvcGVyYXRpbmcgb24uIEJlY2F1c2Ugb2YgdGhpcywgSSBhbHNvIGNhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiBlYWNoIGdyb3VwLCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB3aGVyZSB0aGUgQkVEUyB2YXJpYWJsZSBpcyBtaXNzaW5nLCBhbmQgdGhlIHBlcmNlbnRhZ2Ugb2Ygb2JzZXJ2YXRpb25zIGluIHRoZSBncm91cCB3aGVyZSB0aGUgdmFyaWFibGUgaXMgbWlzc2luZy4gVGhpcyBwcm92aWRlcyBpbXBvcnRhbnQgY29udGV4dCBmb3IgaG93IHJlYWRpbHkgd2UgY2FuIHJlbHkgb24gdGhlc2UgbnVtYmVycy4gRm9yIGluc3RhbmNlLCB3aGVuIHlvdSBydW4gdGhlIGNvZGUgYmVsb3csIG5vdGUgaG93IGluIEFsYXNrYSwgdGhlIG51bWJlciBvZiBiZWRzIGFyZSBtaXNzaW5nIGZvciAyOCUgb2YgdGhlIG9ic2VydmF0aW9ucy4gCgpgYGB7cn0KI1J1biB0aGlzIGNvZGUgY2h1bmsuCgojZGYgJT4lIGdyb3VwX2J5KENBVEVHT1JJQ0FMX1ZBUklBQkxFKSAlPiUgc3VtbWFyaXplKE5FV19WQVJJQUJMRV9OQU1FID0gc3VtKE5VTUJFUklDX1ZBUklBQkxFLCBuYS5ybSA9IFRSVUUpKSAlPiUgdW5ncm91cCgpCgpob3NwaXRhbHMgJT4lIAogIGdyb3VwX2J5KFNUQVRFKSAlPiUgI0dyb3VwIG9ic2VydmF0aW9ucyBieSBzdGF0ZQogIHN1bW1hcml6ZSgKICAgIFNUQVRFU19CRURTID0gc3VtKEJFRFMsIG5hLnJtID0gVFJVRSksICNDYWxjdWxhdGUgdGhlIHN1bSBvZiBCRURTIHdpdGhpbiBlYWNoIFNUQVRFIGdyb3VwCiAgICBPQlNFUlZBVElPTlMgPSBuKCksICNDYWxjdWxhdGUgaG93IG1hbnkgb2JzZXJ2YXRpb25zIGFyZSBpbiBlYWNoIFNUQVRFIGdyb3VwCiAgICBNSVNTSU5HX0JFRFMgPSBzdW0oaXMubmEoQkVEUykpLCAjQ2FsY3VsYXRlIGhvdyBtYW55IE5BcyBhcmUgaW4gdGhlIEJFRFMgdmFyaWFibGUgaW4gZWFjaCBTVEFURSBncm91cAogICAgUEVSQ0VOVF9NSVNTSU5HID0gc3VtKGlzLm5hKEJFRFMpKS9uKCkqMTAwKSAlPiUgI0RpdmlkZSB0aGUgdHdvIHZhbHVlcyB5b3UganVzdCBjYWxjdWxhdGVkIHRvIGRldGVybWluZSB0aGUgcGVyY2VudCBvZiBtaXNzaW5nIGRhdGEKICB1bmdyb3VwKCkKYGBgCgo+IE5vdGljZSB0aGF0IEkgY2xvc2UgZWFjaCBvZiB0aGVzZSBjYWxscyB3aXRoICoqdW5ncm91cCgpKiouIFdoZW4gd2UgZ3JvdXBfYnkoKSBhIHZhcmlhYmxlLCBhbnkgc3Vic2VxdWVudCBmdW5jdGlvbiBjYWxscyB3aWxsIGNvbnRpbnVlIHRvIGJlIHBlcmZvcm1lZCBvbiB0aGUgZ3JvdXBlZCBkYXRhLCB1bmxlc3Mgd2UgdW5ncm91cCgpIGl0LiBUaGlzIGNhbiBiZSBpbXBvcnRhbnQgaWYgd2Ugd2FudCB0byBmaWx0ZXIgdG8gc3BlY2lmaWMgdmFsdWVzIGFmdGVyIHdlIHN1bW1hcml6ZSgpIHRoZSBkYXRhLiBBc3N1bWluZyB0aGF0IHdlIGRvbid0IHdhbnQgdG8gcGVyZm9ybSBhIGZpbHRlciBvcGVyYXRpb24gd2l0aGluIGVhY2ggZ3JvdXAgYnV0IG9uIHRoZSBlbnRpcmUgbmV3IGRhdGFmcmFtZSBjcmVhdGVkIGFmdGVyIHN1bW1hcml6aW5nLCB3ZSBuZWVkIHRvIHVuZ3JvdXAoKSB0aGUgZGF0YSBiZWZvcmUgcGVyZm9ybWluZyB0aGUgZmlsdGVyKCkgb3BlcmF0aW9uLiAKCkZyb20gdGhpcyBmdW5jdGlvbiwgd2Ugc2VlIHRoZSBudW1iZXIgb2YgYmVkcyBhY3Jvc3MgYWxsIGhvc3BpdGFscyBwZXIgc3RhdGUuIERlcGVuZGluZyBvbiB0aGUgcXVlc3Rpb24gd2UgYXJlIGFza2luZywgdGhpcyBtYXkgb3IgbWF5IG5vdCBiZSByZWxldmFudC4gRm9yIGluc3RhbmNlLCBpZiBJJ20gd29uZGVyaW5nIGhvdyBtdWNoIGhvc3BpdGFsIGluZnJhc3RydWN0dXJlIGlzIGF2YWlsYWJsZSB0byBzdXBwb3J0IENvdmlkLTE5IHBhdGllbnRzLCBvbmUgKG9mIGEgbnVtYmVyIG9mIGZhY3RvcnMpIEkgbmVlZCB0byBjb25zaWRlciBiZWZvcmUgcHJlc2VudGluZyB0aGlzIGRhdGEgaXMgd2hpY2ggdHlwZXMgb2YgaG9zcGl0YWxzIGFyZSBhY2NlcHRpbmcgQ292aWQtMTkgcGF0aWVudHMuIEFyZSByZWhhYmlsaXRhdGlvbiBob3NwaXRhbHMgYWNjZXB0aW5nIHBhdGllbnRzPyBQc3ljaGlhdHJpYyBob3NwaXRhbHM/IE1pbGl0YXJ5IGhvc3BpdGFscz8gSWYgdGhleSBhcmVuJ3Qgbm93LCB3aWxsIHRoZXkgYXQgc29tZSBwb2ludD8gRnVydGhlciwgc29tZSBzdGF0ZXMgYXJlIHRhbGtpbmcgYWJvdXQgY29yZG9uaW5nIG9mZiBob3RlbHMgZm9yIENvdmlkLTE5IHBhdGllbnRzLiBIb3cgZG8gd2UgYWNjb3VudCBmb3IgdGhpcyBjaGFuZ2UgaW4gdGhlIG51bWJlciBvZiBob3NwaXRhbCBiZWRzIChzb21ldGhpbmcgZGVmaW5pdGVseSBub3QgcmVwcmVzZW50ZWQgaW4gb3VyIGRhdGEgYmFzZWQgb24gdGhlIHdheSBob3NwaXRhbCBoYXMgYmVlbiBkZWZpbmVkKS4gV2UgbmVlZCB0byBkbyBleHRlcm5hbCByZXNlYXJjaCB0byBhbnN3ZXIgdGhlc2UgcXVlc3Rpb25zLiBUaGVuIHdlIG1heSB3aXNoIHRvIGZpbHRlciBvdXIgZGF0YSB0byByZWxldmFudCBob3NwaXRhbCB0eXBlcy4gRm9yIGluc3RhbmNlLCBhdCB0aGlzIG1vbWVudCwgd2UgbWF5IGZpbHRlciBvdXIgZGF0YSB0byBvbmx5IGluY2x1ZGUgYmVkcyBhdCBHZW5lcmFsIEFjdXRlIENhcmUgSG9zcGl0YWxzLiBXZSBhbHNvIGtub3cgdGhhdCBzb21lIGhvc3BpdGFscyBpbiB0aGUgZGF0YXNldCBhcmUgY2xvc2VkLiBXZSBuZWVkIHRvIGFsc28gZmlsdGVyIHRoZXNlIG91dCBiZWZvcmUgcHJlc2VudGluZyB0aGUgZGF0YS4gTm90aWNlIGhvdyBiZWxvdywgSSBjYW4gZG8gdGhpcyBieSBzaW1wbHkgY29weWluZyBhbmQgcGFzdGluZyB0aGUgY29kZSBmcm9tIGFib3ZlIGFuZCBhZGRpbmcgb25lIGZpbHRlciBzdGF0ZW1lbnQgYmVmb3JlIGdyb3VwaW5nIHRoZSBkYXRhLiAKCmBgYHtyfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIgJiBTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBncm91cF9ieShTVEFURSkgJT4lICNHcm91cCBvYnNlcnZhdGlvbnMgYnkgc3RhdGUKICBzdW1tYXJpemUoCiAgICBTVEFURVNfQkVEUyA9IHN1bShCRURTLCBuYS5ybSA9IFRSVUUpLCAjQ2FsY3VsYXRlIHRoZSBzdW0gb2YgQkVEUyB3aXRoaW4gZWFjaCBTVEFURSBncm91cAogICAgT0JTRVJWQVRJT05TID0gbigpLCAjQ2FsY3VsYXRlIGhvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgaW4gZWFjaCBTVEFURSBncm91cAogICAgTUlTU0lOR19CRURTID0gc3VtKGlzLm5hKEJFRFMpKSwgI0NhbGN1bGF0ZSBob3cgbWFueSBOQXMgYXJlIGluIHRoZSBCRURTIHZhcmlhYmxlIGluIGVhY2ggU1RBVEUgZ3JvdXAKICAgIFBFUkNFTlRfTUlTU0lORyA9IHN1bShpcy5uYShCRURTKSkvbigpKjEwMCkgJT4lICNEaXZpZGUgdGhlIHR3byB2YWx1ZXMgeW91IGp1c3QgY2FsY3VsYXRlZCB0byBkZXRlcm1pbmUgdGhlIHBlcmNlbnQgb2YgbWlzc2luZyBkYXRhCiAgdW5ncm91cCgpCmBgYAoKSW4gb3RoZXIgd29yZHMsIG9mdGVuIHRpbWVzIHRvIGFuc3dlciBxdWVzdGlvbnMgd2l0aGluIGEgZGF0YXNldCwgd2UgbmVlZCB0byBib3RoIHpvb20gaW4gYW5kIG91dCBvbiBkYXRhIC0gaG9uaW5nIGluIG9uIGNlcnRhaW4gb2JzZXJ2YXRpb25zIGFuZCB0aGVuIGdlbmVyYWxpemluZyBhY3Jvc3MgdGhlbS4gV2UgY2Fubm90IGFuc3dlciBxdWVzdGlvbnMgd2VsbCBpZiB3ZSBkb24ndCBoYXZlIGEgZ29vZCB1bmRlcnN0YW5kaW5nIG9mIHdoYXQncyBpbmNsdWRlZCBpbiBvdXIgZGF0YSBhbmQgaG93IGlzc3VlcyBhcmUgZGVmaW5lZC4gSGFkIHdlIG5vdCBrbm93biB0aGF0IGhvc3BpdGFscyB0aGF0IGFyZSBjbG9zZWQgYW5kIGhvc3BpdGFscyB0aGF0IGFyZSBjbGFzc2VkIGFzIHJlaGFicyBvciBwc3ljaGlhdHJpYyBmYWNpbGl0aWVzIHdlcmUgaW5jbHVkZWQgaW4gdGhlIGRhdGEsIHdlIG1heSBoYXZlIG1hZGUgc29tZSBwb29yIGFzc3VtcHRpb25zIGFib3V0IHRoZSBudW1iZXIgb2YgYmVkcyBhdmFpbGFibGUuIEFsc28gbm90ZSBob3csIGluIGV2ZXJ5IHN0ZXAgb2YgZGF0YSBhbmFseXNpcywgd2UgaGF2ZSB0byBtYWtlIGRlY2lzaW9ucyBhYm91dCB3aGF0IHRvIGluY2x1ZGUgYW5kIHdoYXQgdG8gZXhjbHVkZSBpbiB0aGUgYW5hbHlzaXMuIERhdGEgYW5hbHlzdHMgcGxheSBhIHZlcnkgYWN0aXZlIHJvbGUgaW4gc2hhcGluZyB0aGUga25vd2xlZGdlIHRoYXQgZ2V0cyBwcm9kdWNlZCBmcm9tIGRhdGEuIFRoZSBudW1iZXJzIGNhbiBuZXZlciBzcGVhayBmb3IgdGhlbXNlbHZlcy4gCgojIyMgV2hlbiBJIE5lZWQgdG8gWm9vbSBJbiBvciBPdXQKCkZvciBzb21lIG9mIHlvdSwgdGhlc2UgZnVuY3Rpb25zIHdpbGwgYmUgbmVjZXNzYXJ5IHRvIGVtcGxveSBiZWZvcmUgcGVyZm9ybWluZyBvcGVyYXRpb25zIGFjcm9zcyBudW1lcmljIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQuIFRoaXMgaXMgYmVjYXVzZSwgYXMgd2UgbGVhcm5lZCBsYXN0IHdlZWssIHNvbWUgb2YgeW91IGhhdmUgb2JzZXJ2YXRpb25hbCB1bml0cyB0aGF0IHNwYW4gbXVsdGlwbGUgdGltZSBwZXJpb2RzLCBtdWx0aXBsZSBnZW9ncmFwaGllcywgb3IgbXVsdGlwbGUgaXNzdWVzLiBCZWZvcmUgcGVyZm9ybWluZyBhbiBvcGVyYXRpb24gYWNyb3NzIGEgbnVtZXJpYyB2YXJpYWJsZSwgd2UgbmVlZCB0byBlbnN1cmUgYWxsIG9mIHRoZSB2YWx1ZXMgaW4gdGhhdCB2YXJpYWJsZSBhcmUgcmVmZXJyaW5nIHRvIG9ic2VydmF0aW9ucyByZXBvcnRlZCBhY3Jvc3MgdGhlIHNhbWUgdGltZWZyYW1lIG9yIGdlb2dyYXBoaWMgc2NhbGUuCgpJbiB0aGUgaG9zcGl0YWxzIGRhdGFzZXQsIHRoaXMgaXMgbGVzcyBvZiBhIGNvbmNlcm4gYmVjYXVzZSBhcyB3ZSBsZWFybmVkIGxhc3Qgd2VlaywgdGhlIG9ic2VydmF0aW9uYWwgdW5pdCBvZiB0aGUgZGF0YXNldCBpcyBvbmUgdGhpbmcgd2l0aG91dCBxdWFsaWZpZXJzIC0gYSBob3NwaXRhbC4gVGhlIEJFRFMgdmFyaWFibGUgaXMgYWx3YXlzIGdvaW5nIHRvIHJlZmVyIHRvIHRoZSBudW1iZXIgb2YgQkVEUyBhdCBhIGhvc3BpdGFsLgoKV2l0aCB0aGUgd29ybGRfaGVhbHRoX2Vjb24gZGF0YSwgd2UgbGVhcm5lZCBsYXN0IHdlZWsgdGhhdCBldmVyeSBvYnNlcnZhdGlvbiByZWZlcnMgdG8gYSBjb3VudHJ5ICphbmQgYSB5ZWFyKi4gTGV0J3Mgc2F5IHRoYXQgd2Ugd2FudGVkIHRvIGNhbGwgc3VtbWFyeSgpIG9uIGxpZmVfZXhwIHZhcmlhYmxlIHRvIGNvbXBhcmUgbGlmZSBleHBlY3RhbmNpZXMgYWNyb3NzIGNvdW50cmllcy4gV2l0aG91dCBmaXJzdCB6b29taW5nIGluIHRvIHRvIGEgc3BlY2lmaWMgeWVhciwgd2Ugd291bGQgYmUgaW5jbHVkaW5nIG11bHRpcGxlIHZhbHVlcyB0YWtlbiBhdCB0aGUgc2FtZSBwbGFjZSBhdCBkaWZmZXJlbnQgdGltZXMuIExldCdzIGZpbHRlciB0aGUgZGF0YSB0byBvbmx5IGluY2x1ZGUgdGhlIG1vc3QgcmVjZW50IHJlcG9ydGluZyB5ZWFyIGFuZCB0aGVuIGNhbGwgc3VtbWFyeSgpOgoKYGBge3J9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKd29ybGRfaGVhbHRoX2Vjb24gJT4lCiAgZmlsdGVyKHllYXIgPT0gbWF4KHllYXIsIG5hLnJtID0gVFJVRSkpICU+JSAjTm90ZSB0aGF0IHRoaXMgaXMgaG93IHdlIGNhbiBmbGl0ZXIgdG8gdGhlIHJvd3Mgd2l0aCB0aGUgbWF4aW11bSB2YWx1ZSBpbiBhIHZhcmlhYmxlOyBpbiB0aGlzIGNhc2UsIHRoaXMgd291bGQgYmUgdGhlIG1vc3QgcmVjZW50IHllYXIuIAogIHNlbGVjdChsaWZlX2V4cCkgJT4lCiAgc3VtbWFyeSgpCmBgYAoKSW4gcmFyZXIgY2FzZXMsIHdlIHdpbGwgbmVlZCB0byBncm91cF9ieSgpIGFuZCBzdW1tYXJpemUoKSBvdXIgZGF0YSBiZWZvcmUgc3RhdGlzdGljYWxseSBhbmFseXppbmcgaXQuIFRoaXMgaXMgdGhlIGNhc2Ugd2l0aCB0aGUgY2FzZXMgZGF0YXNldC4gRWFjaCBvYnNlcnZhdGlvbiBpbiB0aGUgY2FzZXMgZGF0YXNldCByZWZlcnMgdG8gYSBjb21iaW5hdGlvbiBvZiB0aGluZ3MgLSBhIHByb3ZpbmNlIGFuZCBhIGNvdW50cnkuIFRoZSBpc3N1ZSBpcyB0aGF0IG5vdCBldmVyeSBjb3VudHJ5IGlzIHJlcG9ydGluZyBkYXRhIGF0IHRoZSBwcm92aW5jZSBsZXZlbC4gVGhpcyBtZWFucyB0aGF0IHNvbWV0aW1lcyB0aGUgVG90YWwuQ2FzZXMgdmFyaWFibGUgaXMgcmVmZXJyaW5nIHRvIHRoZSBudW1iZXIgb2YgY2FzZXMgaW4gYSBjb3VudHJ5IGFuZCBzb21ldGltZXMgaXQgaXMgcmVmZXJyaW5nIHRvIHRoZSBudW1iZXIgb2YgY2FzZXMgaW4gYSBQcm92aW5jZS4gSWYgd2Ugd2FudGVkIHRvIHN0YXRpc3RpY2FsbHkgYW5hbHl6ZSB0aGUgbnVtYmVyIG9mIGNhc2VzIGFjcm9zcyBvYnNlcnZhdGlvbnMsIHdlIGZpcnN0IG5lZWQgdG8gdHJhbnNmb3JtIHRoZSBkYXRhc2V0IHNvIHRoYXQgZWFjaCBvYnNlcnZhdGlvbiBpcyByZXBvcnRlZCBhdCB0aGUgc2FtZSBzY2FsZS4gSW4gb3RoZXIgd29yZHMsIHdlIG5lZWQgdG8gem9vbSBvdXQgdG8gc3RhbmRhcmRpemUgdGhlIG9ic2VydmF0aW9uYWwgdW5pdCBhY3Jvc3MgdGhlIGRhdGFzZXQgdG8gdGhlIGNvdW50cnkgbGV2ZWwgKHNpbmNlIHdlIGRvIG5vdCBhbHdheXMgaGF2ZSBkYXRhIGF0IHRoZSBwcm92aW5jZSBsZXZlbCkuIFRvIGRvIHRoYXQsIHdlIHdpbGwgbmVlZCB0byBncm91cF9ieSgpIENvdW50cnkuUmVnaW9uIGFuZCB0aGVuIHN1bW1hcml6ZSB0aGUgc3VtIG9mIFRvdGFsLkNhc2VzLgoKYGBge3J9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKY2FzZXMgJT4lCiAgZ3JvdXBfYnkoQ291bnRyeS5SZWdpb24pICU+JQogIHN1bW1hcml6ZShUb3RhbC5DYXNlcyA9IHN1bShUb3RhbC5DYXNlcywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpCmBgYAoKT25jZSB3ZSd2ZSBkb25lIHRoaXMsIHdlIGNhbiBjb25maWRlbnRseSBzdGF0aXN0aWNhbGx5IGFuYWx5emUgdGhlIFRvdGFsLkNhc2VzIHZhcmlhYmxlIGJlY2F1c2Ugd2Uga25vdyB0aGF0IHRoZSBudW1iZXIgaXMgYWx3YXlzIHJlZmVycmluZyB0byB0aGUgbnVtYmVyIG9mIGNhc2VzIGluIGEgY291bnRyeS4KCkFsdGVybmF0aXZlbHksIHdlIGNvdWxkIGFsc28gZmlsdGVyIHRvIG9uZSBjb3VudHJ5IHRvIGFuYWx5emUgbnVtZXJpYyB2YXJpYWJsZXMgYWNyb3NzIHByb3ZpbmNlcyBpbiB0aGF0IGNvdW50cnkuIElmIEkgd2VyZSB0byBjYWxsIHN1bW1hcnkoKSBvbiB0aGUgVG90YWwuQ2FzZXMgdmFyaWFibGUgaW4gdGhlIGNhc2VzIGRhdGFzZXQsIEkgd291bGQgYmUgZ2F0aGVyaW5nIHN0YXRpc3RpY3MgYWNyb3NzIG51bWJlcnMgcmVwb3J0ZWQgYXQgZGlmZmVyZW50IGdlb2dyYXBoaWMgc2NhbGVzLiBCZWxvdywgSSBmaWx0ZXIgdGhlIGNhc2VzIGRhdGFzZXQgdG8gb25lIENvdW50cnkgLSBDYW5hZGEgLSBzbyB0aGF0IEknbSBnYXRoZXJpbmcgc3RhdGlzdGljcyBhY3Jvc3MgYWxsIHByb3ZpbmNlcyBpbiBDYW5hZGEuIAoKYGBge3J9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKY2FzZXMgJT4lIAogIGZpbHRlcihDb3VudHJ5LlJlZ2lvbiA9PSAiQ2FuYWRhIikgJT4lCiAgc2VsZWN0KFRvdGFsLkNhc2VzKSAlPiUKICBzdW1tYXJ5KCkKYGBgCgpMZXQncyB0ZXN0IHRoZSBleHRlbnQgdG8gd2hpY2ggeW91IHdpbGwgbmVlZCB0byB6b29tIGluIG9yIHpvb20gb3V0IHRvIHN0YXRpc3RpY2FsbHkgYW5hbHl6ZSBudW1lcmljIHZhbHVlcyB5b3VyIGRhdGEuIEkndmUgc2VsZWN0ZWQgYSBudW1lcmljIHZhcmlhYmxlIGZvciBlYWNoIG9mIHlvdXIgZGF0YXNldHMuIENvbW1lbnQgb3V0IHRoZSBsaW5lIHdpdGggeW91ciBkYXRhc2V0IGFuZCBjb21wbGV0ZSB0aGUgc3RhdGVtZW50IGJlbG93LiBUaGluayB3aGF0IHZhcmlhYmxlcyBtYWtlIHVwIHRoZSB1bmlxdWUga2V5IGluIHlvdXIgZGF0YXNldHMuIElmIHlvdSBoYXZlIG1vcmUgdGhhbiBvbmUgdmFyaWFibGUgaW4geW91ciB1bmlxdWUga2V5LCBtYWtlIHN1cmUgdGhhdCBlYWNoIGlzIHJlcHJlc2VudGVkIGluIHlvdXIgc3RhdGVtZW50IGJlbG93LiBBcyBhIGhpbnQsIEkgd2lsbCBub3RlIHRoYXQgb25seSBvbmUgb2YgdGhlIHNpeCBncm91cHMgaGFzIG9ubHkgb25lIHZhcmlhYmxlIGluIHRoZWlyIHVuaXF1ZSBrZXkgKCgqYWhlbSogaW5mcmFzdHJ1Y3R1cmUpLiBUaHJlZSBvZiB0aGUgZ3JvdXBzIGhhdmUgdHdvIHZhcmlhYmxlcywgYW5kIHR3byBncm91cHMgKCphaGVtKiBpbmNvbWUgc2VjdXJpdHkpIGhhdmUgdGhyZWUgdmFyaWFibGVzLiAKCj4gRW52aXJvbm1lbnQgZ3JvdXAgb25seTogT24gaW1wb3J0IHlvdXIgZGF0YSBkb2VzIHJlcXVpcmUgdGhyZWUgdmFyaWFibGVzIHRvIGNvbnN0aXR1dGUgYSB1bmlxdWUga2V5LiBIb3dldmVyLCB3aXRoIHRoZSBjb2RlIGJlbG93LCBJJ20gZ29pbmcgdG8gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGluIHlvdXIgZGF0YXNldCB0byB1bmlxdWVseSByZWZlciB0byBlYWNoIGNvdW50eSBzbyB0aGF0IHlvdSBkbyBub3QgaGF2ZSByZWZlcmVuY2UgYm90aCB0aGUgc3RhdGUgY29kZSBhbmQgdGhlIGNvdW50eSBjb2RlIHRvIHJlZmVyIHRvIGEgY291bnR5LiBUaGlzIHZhcmlhYmxlIHdpbGwgYmUgY2FsbGVkIGZpcHMsIGFuZCBpdCB3aWxsIGFwcGVhciBhcyB0aGUgbGFzdCB2YXJpYWJsZSBpbiB0aGUgZGF0YXNldC4gCgpgYGB7cn0KI0Vudmlyb25tZW50IGdyb3VwIG9ubHk6IHVuY29tbWVudCB0aGlzIGxpbmUgdG8gY3JlYXRlIHRoaXMgbmV3IHZhcmlhYmxlLiBSZXNwb25kIHRvIHRoZSBxdWVzdGlvbnMgYmVsb3cgd2l0aCB0aGlzIGNoYW5nZSBpbiB0aGUgZGF0YXNldC4KCiNhcWkgPC0gYXFpICU+JSBtdXRhdGUoZmlwcyA9IHBhc3RlKHN0cl9wYWQoYXMuY2hhcmFjdGVyKHN0YXRlQ29kZSksIDIsIHNpZGUgPSAibGVmdCIsICIwIiksIHN0cl9wYWQoYXMuY2hhcmFjdGVyKGNvdW50eUNvZGUpLCAzLCBzaWRlID0gImxlZnQiLCAiMCIpLCBzZXAgPSIiKSkKYGBgCgpgYGB7cn0KI1VuY29tbWVudCB0aGUgbGluZSBhc3NvY2lhdGVkIHdpdGggeW91ciBkYXRhc2V0IGFuZCBmaWxsIGluIHRoZSBibGFuay4gVGhlbiBydW4gdGhlIGNvZGUuCgojcGFzdGUoZGYkTlVNRVJJQ19WQVJJQUJMRVsxXSwgInJlZmVycyB0byBhIG51bWJlci9tZWFzdXJlIG9mIFtGSUxMIE5VTUVSSUMgVkFSSUFCTEVdIGluIGEgX19fX18gaW4gbXkgZGF0YXNldC4iKQoKI0V4YW1wbGU6CnBhc3RlKGhvc3BpdGFscyRCRURTWzFdLCAicmVmZXJzIHRvIGEgbnVtYmVyIG9mIGJlZHMgaW4gYSBob3NwaXRhbCBpbiBteSBkYXRhc2V0LiIpCnBhc3RlKHdvcmxkX2hlYWx0aF9lY29uJHBvcFsxXSwgInJlZmVycyB0byBhIG51bWJlciBvZiBwZW9wbGUgaW4gYSBjb3VudHJ5IGluIGEgZ2l2ZW4geWVhciBpbiBteSBkYXRhc2V0LiIpCnBhc3RlKGNhc2VzJFRvdGFsLkNhc2VzWzFdLCAicmVmZXJzIHRvIGEgbnVtYmVyIG9mIGNhc2VzIGluIGEgY291bnRyeSBhbmQvb3IgcHJvdmluY2UgaW4gbXkgZGF0YXNldC4iKQoKI3Bhc3RlKGRvbV92aW9sZW5jZV9jYWxscyRUT1RBTF9DQUxMU1sxXSwgInJlZmVycyB0byBhIG51bWJlciBvZiBjYWxscyBpbiBhIF9fX19fIGluIG15IGRhdGFzZXQuIikKI3Bhc3RlKGFxaSRudW1iZXJTaXRlc1JlcG9ydGluZ1sxXSwgInJlZmVycyB0byB0aGUgbnVtYmVyIG9mIHNpdGVzIHJlcG9ydGluZyBpbiBhIF9fX19fIGluIG15IGRhdGFzZXQuIikKI3Bhc3RlKGludGVybmV0X21hc3Rlcl9wbGFuJHRvdGFsX251bWJlcl9vZl9ob3VzZWhvbGRzWzFdLCAicmVmZXJzIHRvIGEgbnVtYmVyIG9mIGhvdXNlaG9sZHMgaW4gYSBfX19fXyBpbiBteSBkYXRhc2V0LiIpCnBhc3RlKGlwcHMkVG90YWwuRGlzY2hhcmdlc1sxXSwgInJlZmVycyB0byBhIG51bWJlciBvZiBkaXNjaGFyZ2VzIGluIGEgZ2l2ZW4gaG9zcGl0YWwgYmFzZWQgb24gYSBkaWFnbm9zaXMgY2xhc3NpZmljYXRpb24gaW4gbXkgZGF0YXNldC4iKQojcGFzdGUoc25hcCRjZXJ0ZWFybmF2Z1sxXSwgInJlZmVycyB0byBhIG1lYXN1cmUgb2YgZWFybmluZ3MgaW4gYSBfX19fXyBpbiBteSBkYXRhc2V0LiIpCiNwYXN0ZShzZWxmX3N1ZmZpY2llbmN5X2NhJGhvdXNpbmdDb3N0c1sxXSwgInJlZmVycyB0byBhIG1lYXN1cmUgb2YgaG91c2luZyBjb3N0cyBpbiBhIF9fX19fIGluIG15IGRhdGFzZXQuIikKYGBgCgpIb3cgZGlkIHlvdSBmaWxsIGluIHRoZSBsYXN0IF9fX19fPyAKCklzIHlvdXIgb2JzZXJ2YXRpb25hbCB1bml0IG9uZSB0aGluZyAoZS5nLiBvbmUgaG9zcGl0YWwsIG9yIG9uZSBjb3VudHJ5KT8gSWYgdGhpcyBpcyB0aGUgY2FzZSwgaXQgd2lsbCBsaWtlbHkgbm90IGJlIGFzIGVzc2VudGlhbCBmb3IgeW91IHRvIHpvb20gaW4gb3Igem9vbSBvdXQgYmVmb3JlIG9wZXJhdGluZyBvbiBudW1lcmljIHZhcmlhYmxlcy4gKipJZiBzbywgd2Ugd2lsbCBzYXkgdGhhdCB5b3UgZG8gbm90IGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uLioqCgpPUiAKCklzIHlvdXIgb2JzZXJ2YXRpb25hbCB1bml0IGEgY29tYmluYXRpb24gb2YgdGhpbmdzIG9yIGZhY3RvcnMgKGUuZy4gb25lIGNoZW1pY2FsIHJlcG9ydGVkIGF0IGEgcGFydGljdWxhciBmYWNpbGl0eSBvciBvbmUgY2Vuc3VzIHRyYWN0IHJlcG9ydGluZyBpbiBhIHBhcnRpY3VsYXIgeWVhcik/IElmIHRoaXMgaXMgdGhlIGNhc2UsIGl0IHdpbGwgbGlrZWx5IGJlIGVzc2VudGlhbCBmb3IgeW91IHRvIHpvb20gaW4gb3Igem9vbSBvdXQgYmVmb3JlIG9wZXJhdGluZyBvbiBudW1lcmljIHZhcmlhYmxlcy4gKipJZiBzbywgd2Ugd2lsbCBzYXkgdGhhdCB5b3UgZG8gaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24uKioKCkZvciBlYWNoIG9mIHRoZSBncm91cHMgdGhhdCBoYXMgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uIChtb3N0IG9mIHlvdSBkbyksIGluIHNvbWUgcGxhY2VzIHRocm91Z2hvdXQgdGhpcyBsYWIsIHlvdSB3aWxsIG5lZWQgdG8gZmlsdGVyIHlvdXIgZGF0YSB0byBwYXJ0aWN1bGFyIG9ic2VydmF0aW9ucyBiZWZvcmUgYW5hbHl6aW5nIGFjcm9zcyBhIHZhcmlhYmxlLiBUaGlzIGlzIGJlY2F1c2Ugd2Ugd2lsbCBiZSBzdW1tYXJpemluZyBpbmZvcm1hdGlvbiBhY3Jvc3MgZ3JvdXBzIG9mIGRhdGEsIGFuZCBpdCB3aWxsIGJlIGltcG9ydGFudCB0byBlbnN1cmUgdGhhdCB5b3UgYXJlIHN1bW1hcml6aW5nIGluZm9ybWF0aW9uIGFjcm9zcyBsaWtlIG9ic2VydmF0aW9ucy4KClRoaW5rIGFib3V0IHdoYXQgeW91IG1pZ2h0IGZpbHRlciB0byBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCB5b3Ugd2lsbCBiZSBjb21wYXJpbmcgbGlrZSBvYnNlcnZhdGlvbnMgKGhpbnQ6IGl0IHdpbGwgaW52b2x2ZSBhIHZhcmlhYmxlIGluIHlvdXIgdW5pcXVlIGtleSkuIFBlcmhhcHMgeW91IHdpbGwgZmlsdGVyIHRvIHRoZSBtb3N0IHJlY2VudCB5ZWFyLCBzbyB0aGF0IHlvdSBjYW4gY29tcGFyZSBvYnNlcnZhdGlvbnMgYWNyb3NzIGdlb2dyYXBoaWVzIGluIHRoYXQgeWVhci4gT3IgcGVyaGFwcyB5b3Ugd2lsbCBmaWx0ZXIgdG8gYSBwYXJ0aWN1bGFyIGdlb2dyYXBoeSwgc28gdGhhdCB5b3UgY2FuIGNvbXBhcmUgb2JzZXJ2YXRpb25zIGFjcm9zcyB0aW1lIGluIHRoYXQgZ2VvZ3JhcGh5LiBPciBwZXJoYXBzIHlvdSB3aWxsIGZpbHRlciB0byBhIHBhcnRpY3VsYXIgZGlhZ25vc2lzIGdyb3VwLCBzbyB0aGF0IHlvdSBjYW4gY29tcGFyZSBjb3N0cyBhY3Jvc3MgaG9zcGl0YWxzIGZvciB0aGF0IGRpYWdub3Npcy4gT3IgcGVyaGFwcyB5b3Ugd2lsbCBmaWx0ZXIgdG8gYSBwYXJ0aWN1bGFyIHllYXIgYW5kIGZhbWlseSB0eXBlIHNvIHRoYXQgeW91IGNhbiBjb21wYXJlIG9ic2VydmF0aW9ucyBhY3Jvc3MgY291bnRpZXMgaW4gdGhhdCB5ZWFyIGZvciB0aGF0IGZhbWlseSB0eXBlLiBDaGFyYWN0ZXJpemUgb25lIHdheSB5b3UgbWlnaHQgZmlsdGVyIHlvdXIgZGF0YSBiZWxvdy4gQmUgc3BlY2lmaWMuIFdoaWNoIHZhcmlhYmxlIGluIHRoZSBkYXRhc2V0IHdpbGwgeW91IGZpbHRlciBvbiBhbmQgdG8gd2hhdCB2YWx1ZShzKSB3aWxsIHlvdSBmaWx0ZXIgaXQgdG8/CgpgYGB7ciBldmFsPUZBTFNFfQpJIHdpbGwgZmlsdGVyIG15IGRhdGEgdG8gdGhlIHZhcmlhYmxlcyBEUkcuRGVmaW5pdGlvbiwgYW5kIEkgd2lsbCBmaWx0ZXIgdGhlIHZhbHVlcyB0byBjaGVzdCBwYWluIGRpYWdub3NlcyBhY3Jvc3MgaG9zcGl0YWxzLgpgYGAKCiMjIyBab29taW5nIGluIGFuZC9vciBab29taW5nIE91dCBvbiBZb3VyIE93biBEYXRhCgpTZWxlY3Qgb25lIG9mIHRoZSB2YWx1ZXMgdGhhdCB5b3UgaWRlbnRpZmllZCBmcm9tIGNhbGxpbmcgZGlzdGluY3QoKSBvbiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGluIGxhc3Qgd2VlaydzIGxhYi4gRmlsdGVyIHRoZSBkYXRhc2V0IHRvIHRoZSByb3dzIHJlcHJlc2VudGluZyB0aGF0IHZhbHVlLCBzZWxlY3QgYSBudW1lcmljIHZhcmlhYmxlIHRvIGV4cGxvcmUsIGFuZCB0aGVuIGNhbGwgc3VtbWFyeSgpLiBJZiB5b3UgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24sIGJlIHN1cmUgdG8gZmlyc3Qgem9vbSBpbnRvIGEgc2V0IG9mIG9ic2VydmF0aW9ucyBpbiB5b3VyIGRhdGEgKHVzaW5nIGZpbHRlcigpKS4gCgpgYGB7cn0KI1VuY29tbWVudCB0aGUgYXBwcm9wcmlhdGUgbGluZXMgYmVsb3csIGFuZCBmaWxsIGluIHlvdXIgZGF0YSBmcmFtZSwgdmFyaWFibGVzLCBhbmQgdmFsdWUuIFJ1biB0aGUgY29kZS4KCiNfX19fXyAlPiUgZmlsdGVyKF9fX19fID09ICJfX19fXyIpICU+JSBzZWxlY3QoX19fX18pICU+JSBzdW1tYXJ5KCkKCiNpcHBzICU+JSBmaWx0ZXIoRFJHLkRlZmluaXRpb24gPT0gIjMxMyAtIENIRVNUIFBBSU4iKSAlPiUgc2VsZWN0KFRvdGFsLkRpc2NoYXJnZXMpICU+JSBzdW1tYXJ5KCkKCiNJZiB5b3UgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24KaXBwcyAlPiUgZmlsdGVyKERSRy5EZWZpbml0aW9uID09ICIzMTMgLSBDSEVTVCBQQUlOIikgJT4lIHNlbGVjdChBdmVyYWdlLlRvdGFsLlBheW1lbnRzKSAlPiUgc3VtbWFyeSgpCgojSW5jb21lIHNlY3VyaXR5IGdyb3VwIG9ubHkKI19fX19fICU+JSBmaWx0ZXIoX19fX18gPT0gX19fX18gJiBfX19fXyA9PSBfX19fXyAmIF9fX19fID09ICJfX19fXyIpICU+JSBzZWxlY3QoX19fX18pICU+JSBzdW1tYXJ5KCkKYGBgCgpXaGF0IHF1ZXN0aW9uIG1pZ2h0IHRoaXMgYW5hbHlzaXMgaGVscCB0byBhZGRyZXNzPwoKYGBge3IgZXZhbD1GQUxTRX0KQSBxdWVzdGlvbiB0aGF0IHRoaXMgYW5hbHlzaXMgbWlnaHQgaGVscCBtZSB0byBhZGRyZXNzIHdvdWxkIGJlIHdoYXQgaXMgdGhlIHZhcmlhdGlvbiBpbiB0aGUgYXZlcmFnZSB0b3RhbCBwYXltZW50cyBmb3IgY2hlc3QgcGFpbiByZWxhdGVkIGRpYWdub3NpcyBhY3Jvc3MgaG9zcGl0YWxzIGluIHRoZSBVUy4KYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gKEZvciBpbnN0YW5jZSwgZm9yIHRoZSBob3NwaXRhbHMgZGF0YXNldCB3ZSBuZWVkZWQgdG8gZmlsdGVyIHRvIGhvc3BpdGFscyB0aGF0IHdlcmUgb3BlbiBpbiBvcmRlciB0byBhZGRyZXNzIHF1ZXN0aW9ucyBhYm91dCBpbmZyYXN0cnVjdHVyZSkuIEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgY29kZSBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpObyBvdGhlciB2YXJpYWJsZXMgaW4gbXkgZGF0YXNldCBuZWVkIHRvIGJlIGNvbnNpZGVyZWQuCmBgYAoKV2hhdCBlbHNlIHdvdWxkIHdlIG5lZWQgdG8ga25vdyB0byBmdWxseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IEhlcmUgeW91IG1heSBjb25zaWRlciB3aGF0IHlvdSBrbm93IGFib3V0IGhvdyB0aGlzIGRhdGFzZXQgd2FzIHByb2R1Y2VkIGFuZCBpdHMgbGltaXRhdGlvbnMuCgpgYGB7ciBldmFsPUZBTFNFfQpUaGVyZSBhcmUgbGltaXRhdGlvbnMgdG8gdGhpcyBkYXRhc2V0LiBGb3IgaW5zdGFuY2UsIHdlIHdvdWxkIG5lZWQgdG8ga25vdyBleGFjdGx5IHdoYXQgY29uZGl0aW9ucyB3b3VsZCBiZSBjbGFzc2lmaWVkIGFzICJDaGVzdCBQYWluIiwgYW5kIGl0IHdvdWxkIGJlIGhlbHBmdWwgdG8ga25vdyB3aHkgdGhpcyB3YXMgdGhlIHByaW1hcnkgZGlhZ25vc2lzIGFuZCB3aGV0aGVyIHRoZXJlIHdlcmUgb3RoZXIgc3ltcHRvbXMgYXNzb2NpYXRlZCB3aXRoIGl0IGFzIHdlbGwuIEZ1cnRoZXJtb3JlLCBpdCB3b3VsZCBiZSBoZWxwZnVsIHRvIGtub3cgd2hhdCB0cmF0bWVudHMgYXJlIGRvbmUgZm9yIHRoaXMgdHlwZSBvZiBkaWFnbm9zaXMsIGFuZCB3aGV0aGVyIGVhY2ggaG9zcGl0YWwgaGFzIGRpZmZlcmVudCBjcml0ZXJpYSB3aGVuIGRpYWdub3NpbmcgY2hlc3QgcGFpbi4KYGBgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gY2FsbGluZyBzdW1tYXJ5KCkgb24geW91ciBmaWx0ZXJlZCBkYXRhc2V0PwoKYGBge3IgZXZhbD1GQUxTRX0KT25lIGluc2lnaHQgdGhhdCBJIGNhbiBkcmF3IGZyb20gY2FsbGluZyBzdW1tYXJ5KCkgaXMgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbWluaW11bSBhbmQgbWF4aW11bSBhdmVyYWdlIHBheW1lbnRzIGZvciBjaGVzdCBwYWluIGRpc2dub3Npcy4gVGhpcyBtaWdodCBiZSBkdWUgdG8gZGlmZmVyZW50IHRyZWF0bWVudHMgcGVyZm9ybWVkLCBsZW5ndGhzIG9mIHN0YXkgb2YgcGF0aWVudHMsIGFuZCB2YXJpYXRpb24gaW4gaG9zcGl0YWwgZXhwZW5zZXMuCmBgYAoKU2VsZWN0IGEgbnVtZXJpYyB2YXJpYWJsZSBpbiB5b3VyIGRhdGFzZXQgdGhhdCByZXByZXNlbnRzIHRoZSBleHRlbnQgb3Igc2NhbGUgb2YgdGhlIGlzc3VlIHlvdSBhcmUgc3R1ZHlpbmcuIFBpY2sgYSBudW1iZXIgdGhhdCB5b3UgYmVsaWV2ZSBzZXJ2ZXMgYXMgYSBnb29kIGluZGljYXRvciB0aGF0IHRoaXMgaXNzdWUgaXMgYXQgYSBub3RhYmxlIGV4dGVudCBvciBzY2FsZSwgYW5kIGZpbHRlciB0aGUgZGF0YXNldCB0byBhbGwgdGhlIHJvd3MgZ3JlYXRlciB0aGFuIChvciBsZXNzIHRoYW4pIHRoaXMgbnVtYmVyLiBDaGVjayB0aGUgcmVtYWluaW5nIGRpc3RpbmN0IHZhbHVlcyBpbiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGluIHRoZSBkYXRhc2V0LiBJZiB5b3UgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24sIGJlIHN1cmUgdG8gZmlyc3Qgem9vbSBpbnRvIGEgc2V0IG9mIG9ic2VydmF0aW9ucyBpbiB5b3VyIGRhdGEgKHVzaW5nIGZpbHRlcigpKS4KCmBgYHtyfQojVW5jb21tZW50IHRoZSBhcHByb3ByaWF0ZSBsaW5lcyBiZWxvdywgYW5kIGZpbGwgaW4geW91ciBkYXRhIGZyYW1lLCB2YXJpYWJsZXMsIGNvbmRpdGlvbiwgYW5kIHZhbHVlLiBSdW4gdGhlIGNvZGUuCiNfX19fXyAlPiUgZmlsdGVyKF9fX19fIF9fX19fIF9fX19fKSAlPiUgZGlzdGluY3QoX19fX18pCgojSWYgeW91IGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uCmlwcHMgJT4lIGZpbHRlcihEUkcuRGVmaW5pdGlvbiA9PSAiMzEzIC0gQ0hFU1QgUEFJTiIgJiBUb3RhbC5EaXNjaGFyZ2VzID4gMTgwKSAlPiUgZGlzdGluY3QoUHJvdmlkZXIuTmFtZSwgVG90YWwuRGlzY2hhcmdlcywgUHJvdmlkZXIuQ2l0eSwgUHJvdmlkZXIuU3RhdGUpCgojSW5jb21lIHNlY3VyaXR5IGdyb3VwIG9ubHkKI19fX19fICU+JSBmaWx0ZXIoX19fX18gPT0gX19fX18gJiBfX19fXyA9PSBfX19fXyAmIF9fX19fIF9fX19fIF9fX19fKSAlPiUgZGlzdGluY3QoX19fX18pCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGlzIGFuYWx5c2lzIGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9ClRoaXMgYW5hbHlzaXMgbWlnaHQgaGVscCBtZSBhZGRyZXNzIHdoYXQgYXJlIHRoZSBob3NwaXRhbHMgd2l0aCB0aGUgaGlnaGVzdCBudW1iZXIgb2YgcGFpZW50cyBkaXNtaXNzZWQgdGhhdCBoYWQgYSBjaGVzdCBwYWluIGRpYWdub3Npcy4gCmBgYAoKQXJlIHRoZXJlIGFueSBvdGhlciB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IHRoYXQgeW91IG5lZWQgdG8gdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIGRpcmVjdGluZyB0aGlzIGFuYWx5c2lzIHRvd2FyZHMgYW5zd2VyaW5nIHRoYXQgcXVlc3Rpb24/IEluIG90aGVyIHdvcmRzLCBkbyB5b3UgbmVlZCB0byB6b29tIGludG8gYW55IHNwZWNpZmljIGFyZWFzIG9mIHRoZSBkYXRhc2V0IChieSBmaWx0ZXJpbmcpIGluIG9yZGVyIHRvIGFwcHJvcHJpYXRlbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBJZiBzbywgd2hpY2g/IEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgY29kZSBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpJdCB3b3VsZCBiZSBoZWxwZnVsIHRvIGtub3cgd2hlcmUgdGhlc2UgaG9zcGl0YWxzIGFyZSBsb2NhdGVkIGFuZCBpbiB3aGF0IFVTIFN0YXRlLiAgCmBgYAoKV2hhdCBlbHNlIHdvdWxkIHdlIG5lZWQgdG8ga25vdyB0byBmdWxseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IEhlcmUgeW91IG1heSBjb25zaWRlciB3aGF0IHlvdSBrbm93IGFib3V0IGhvdyB0aGlzIGRhdGFzZXQgd2FzIHByb2R1Y2VkIGFuZCBpdHMgbGltaXRhdGlvbnMuCgpgYGB7ciBldmFsPUZBTFNFfQpJdCB3b3VsZCBiZSBoZWxwZnVsIHRvIHNlZSBob3cgdGhlc2UgaG9zcGl0YWxzIGNsYXNzaWZ5IGNoZXN0IHBhaW4gZGlhZ25vc2lzLCBhbmQgd2hhdCB0eXBlIG9mIGNyaXRlcmlhIHRoZXkgdXNlLgpgYGAKCldoYXQgaW5zaWdodCBjYW4geW91IGRyYXcgZnJvbSBjYWxsaW5nIGRpc3RpbmN0IG9uIHRoZSBmaWx0ZXJlZCBkYXRhPwoKYGBge3IgZXZhbD1GQUxTRX0KRnJvbSBjYWxsaW5nIGRpc3RpbmN0IG9uIG15IGZpbHRlcmVkIGRhdGEgSSBjYW4gc2VlIHRoZSBuYW1lIGFuZCBjaXR5IG9mIHRoZSBmZXcgaG9zcGl0YWxzIHRoYXQgaGF2ZSBtb3JlIHRoYW4gMTgwIGRpc2NoYXJnZXMgb2YgcGF0aWVudHMgZGlhZ25vc2VkIHdpdGggY2hlc3QgcGFpbiwgYW5kIEkgY2FuIGFsc28gc2VlIHRoYXQgdGhleSBhcmUgbG9jYXRlZCBpbiBOZXcgWW9yaywgVGV4YXMsIGFuZCBNaWNoaWdhbi4gVGhpcyBjb3VsZCBoZWxwIG1lIG5hcnJvdyBkb3duIG15IHJlc2VhcmNoIHRvIHRyeSBleHBsYWluIHdoeSB0aGVzZSBob3BzaXRhbHMgaGF2ZSBzdWNoIGEgaGlnaCBudW1iZXIgb2YgY2hlc3QgcGFpbiBkaWFnbm9zZXMsIGFuZCB3aGV0aGVyIGl0IGhhcyB0byBkbyB3aXRoIHRoZSB3YXkgdGhleSBjbGFzc2lmeSBpdC4KYGBgCgpTZWxlY3QgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB0aGF0IHlvdSB3b3VsZCBsaWtlIHRvIGdyb3VwIHlvdXIgZGF0YSBieSwgc28gdGhhdCB5b3UgY2FuIHN1bW1hcml6ZSBzb21lIHN0YXRpc3RpY3MgYWNyb3NzIGVhY2ggZ3JvdXBpbmcuIFlvdSBtYXkgZ3JvdXAgeW91ciBkYXRhIGJ5IGEgcGFydGljdWxhciB5ZWFyLCBieSBhIHBhcnRpY3VsYXIgbG9jYXRpb24gKHN1Y2ggYXMgYSBzdGF0ZSBvciBhIHJlZ2lvbiksIG9yIGJ5IGEgcGFydGljdWxhciBjYXRlZ29yeS4gVGhlbiBzZWxlY3QgYSBudW1lcmljIHZhcmlhYmxlIGluIHlvdXIgZGF0YXNldCB0byBzdW1tYXJpemUgYnkuIEZvciBpbnN0YW5jZSwgeW91IG1heSB3YW50IHRvIHN1bSB0aGUgdG90YWwgbnVtYmVyIG9mIHJlcG9ydHMgaW4gYSBnaXZlbiB5ZWFyLCBvciBmaW5kIHRoZSBhdmVyYWdlIG51bWJlciBvZiBjYXNlcyByZXBvcnRlZCBpbiBhIGNlcnRhaW4gc3RhdGUuIEFsc28gY2FsY3VsYXRlIHRoZSBwZXJjZW50IG9mIG9ic2VydmF0aW9ucyB3aGVyZSBkYXRhIGlzIG1pc3NpbmcgaW4gZWFjaCBncm91cC4gSWYgeW91IGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uLCB5b3UgbWF5IHdhbnQgdG8gZ3JvdXAgdGhlIGRhdGEgYnkgb25lIG9mIHRoZSB2YXJpYWJsZXMgaW4geW91ciB1bmlxdWUga2V5LiBGb3IgaW5zdGFuY2UsIGlmIHlvdXIgdW5pcXVlIGtleSBpcyBhIGNvdW50eSBhbmQgeWVhciwgdGhlbiBwZXJoYXBzIHlvdSB3YW50IHRvIGdyb3VwIHRoZSBkYXRhIGJ5IGNvdW50eSBhbmQgc3VtbWFyaXplIHNvbWV0aGluZyBhY3Jvc3MgZWFjaCB5ZWFyLiBJZiB5b3UgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24gYW5kIGNob29zZSB0byBncm91cCBieSBhIHZhcmlhYmxlIHRoYXQgaXMgbm90IGluIHlvdXIgdW5pcXVlIGtleSwgdGhlbiBiZSBzdXJlIHRvIGZpbHRlciB0aGUgZGF0YSBhcyB5b3UgaGF2ZSBiZWVuIGFib3ZlLiAKCmBgYHtyfQojVW5jb21tZW50IHRoZSBhcHByb3ByaWF0ZSBsaW5lcyBiZWxvdywgYW5kIGZpbGwgaW4geW91ciBkYXRhIGZyYW1lLCB2YXJpYWJsZXMsIGFuZCBzdW1tYXJpemUgdmFyaWFibGUgbmFtZSwgYW5kIG1hdGggZnVuY3Rpb24uIFRoZW4gcnVuIHRoZSBjb2RlLgoKaXBwcyAlPiUgZ3JvdXBfYnkoRFJHLkRlZmluaXRpb24pICU+JSBzdW1tYXJpemUoVG90YWwuRGlzY2hhcmdlcy5EUkcgPSBzdW0oVG90YWwuRGlzY2hhcmdlcywgbmEucm0gPSBUUlVFKSwgT0JTRVJWQVRJT05TID0gbigpLCBNSVNTSU5HID0gc3VtKGlzLm5hKFRvdGFsLkRpc2NoYXJnZXMpKSwgUEVSQ0VOVF9NSVNTSU5HID0gc3VtKGlzLm5hKFRvdGFsLkRpc2NoYXJnZXMpKS9uKCkqMTAwKQoKI0lmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbiAoYW5kIG5vdCBncm91cGluZyBieSB0aGUgcXVhbGlmaWVyKS4KI19fX19fICU+JSBmaWx0ZXIoX19fX18gPT0gX19fX18pICU+JSBncm91cF9ieShfX19fXykgJT4lIHN1bW1hcml6ZShfX19fXyA9IF9fX19fKF9fX19fLCBuYS5ybSA9IFRSVUUpLCBPQlNFUlZBVElPTlMgPSBuKCksIE1JU1NJTkcgPSBzdW0oaXMubmEoX19fX18pKSwgUEVSQ0VOVF9NSVNTSU5HID0gc3VtKGlzLm5hKEJFRFMpKS9uKCkqMTAwKQpgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBhbmFseXNpcyBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpUaGlzIGFuYWx5c2lzIGNvdWxkIG1haW5seSBoZWxwaW5nIG1lIGFkZHJlc3MgdGhlIHF1ZXN0aW9uIGFib3V0IGhvdyBtYW55IHR5cGVzIG9mIGNsYXNzaWZpY2F0aW9ucyBkaWFnbm9zZXMgZXhpc3QgaW4gdGhpcyBkYXRhc2V0LCBhbmQgd2hhdCB0aGUgdG90YWwgbnVtYmVyIG9mIHBhdGllbnRzIGRpYWdub3NlZCB3aXRoIGVhY2ggY29uZGl0aW9uIGlzLiAKYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gQmUgc3VyZSB0byBhZGp1c3QgeW91ciBwbG90IGFib3ZlIHRvIHJlZmxlY3QgdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9Ck5vLCB0aGVyZSBhcmUgbm90LgpgYGAKCldoYXQgZWxzZSB3b3VsZCB3ZSBuZWVkIHRvIGtub3cgdG8gZnVsbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBIZXJlIHlvdSBtYXkgY29uc2lkZXIgd2hhdCB5b3Uga25vdyBhYm91dCBob3cgdGhpcyBkYXRhc2V0IHdhcyBwcm9kdWNlZCBhbmQgaXRzIGxpbWl0YXRpb25zLgoKYGBge3IgZXZhbD1GQUxTRX0KSSB3b3VsZCBuZWVkIHRvIGFja25vd2xlZGdlIHRoYXQgdGhlcmUgYXJlIHNvIG1hbnkgcG9zc2libGUgdmFyaWF0aW9ucyBpbiBjbGFzc2lmeWluZyBkaWFnbm9zZXMsIGFuZCB0aGF0IG1hbnkgb2YgdGhlc2UgY2xhc3NpZmljYXRpb25zIHBvdGVudGlhbGx5IGdyb3VwIHRvZ2V0aGVyIGRpZmZlcmVudCBjb25kaXRpb25zIGluIG9uZSBkaWFnbm9zaXMuIElmIHRoaXMgZGF0YXNldCB3ZXJlIHRvIGNvbnNpZGVyIGFsbCBwb3NzaWJsZSB2YXJpYXRpb25zIGFuZCBjb25kaXRpb25zLCB0aGUgbnVtYmVyIG9mIGRpYXNnbm9zZXMgd291bGQgbXVjaCBtdWNoIGhpZ2hlci4gQWxzbywgcGF0aWVudHMgdGhhdCBoYXZlIGJlZW4gY2xhc3NpZmllZCB3aXRoIG9uZSBvZiB0aGVzZSBkaWFnbm9zZXMgbWlnaHQgYWxzbyBoYXZlIG90aGVyIGNvbmRpdGlvbnMgdGhhdCBhcmUgbm90IHJlZ2lzdGVyZWQsIGFzIHBhdGllbnRzIG9ubHkgaGF2ZSBhIHByaW1hcnkgZGlhZ25vc2lzIHJlZ2lzdGVyZWQuIApgYGAgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gZ3JvdXBpbmcgYW5kIHN1bW1hcml6aW5nPwoKYGBge3IgZXZhbD1GQUxTRX0KSSBjYW4gc2VlIHdoYXQgdGhlIG1vc3QgY29tbW9uIGRpYWdub3NlcyBhcmUsIGFuZCBob3cgbWFueSBwYXRpZW50cyByZWNlaXZlIHRoYXQgZGlhZ25vc2lzLiBBbHNvLCBJIGNhbiBzZWUgd2hhdCB0aGUgcmFyZXN0IGRpYWdub3NlcyBhbmQgcHJvY2VkdXJlcyBhcmUuIEFsc28sIEkgY2FuIHNlZSBmcm9tIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGhvdyBtYW55IGhvc3BpdGFscyBoYXZlIGF0IGxlYXN0IDEgc3BlY2lmaWMgZGlhZ25vc2lzLiBGb3IgaW5zdGFuY2UsIEkgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBhIHRvdGFsIG9mIDI4IHBhdGllbnRzIGRpYWdub3NlZCB3aXRoIEFVVE9MT0dPVVMgQk9ORSBNQVJST1cgVFJBTlNQTEFOVCBXL08gQ0MvTUNDLCBidXQgb25seSAyIG9ic2VydmF0aW9ucywgd2hpY2ggbWVhbnMgdGhhdCBvbmx5IDIgaG9zcGl0YWxzIGhhdmUgcGVyZm9ybWVkIHRoaXMgdHlwZSBvZiBwcm9jZWR1cmUuIFRoaXMgY291bGQgdGVsbCBtZSB0aGF0IHRoaXMgdHlwZSBvZiBwcm9jZWR1cmUgYXNzb2NpYXRlZCB3aXRoIHRoaXMgZGlhZ25vc2lzIGlzIHByZXR0eSByYXJlIGFuZCBtaWdodCBiZSBvbmx5IHBlcmZvcm1lZCBpbiBhIGNvdXBsZSBvZiBob3NwaXRhbHMgaW4gdGhlIFVTIHdoaWNoIG1pZ2h0IGJlIHNwZWNpYWxpemVkIGFuZCBlcXVpcHBlZCB0byB0cmVhdCBzdWNoIGNvbmRpdGlvbi4gCmBgYAoKQ29tYmluZSBhbnkgY29tYmluYXRpb24gb2YgdGhlIDQgdmVyYnMgd2UgbGVhcm5lZCBpbiBjbGFzcyB0aGlzIHdlZWsgb3IgbGFzdCAoc2VsZWN0LCBmaWx0ZXIsIGdyb3VwIGJ5LCBvciBzdW1tYXJpemUpIHRvIGV4cGxvcmUgeW91ciBkYXRhc2V0IGZ1cnRoZXIuIFlvdSBtYXkgYWxzbyB1c2UgYXJyYW5nZSwgc3VtbWFyeSwgb3IgZGlzdGluY3QuIAoKYGBge3J9CgppcHBzICU+JSBmaWx0ZXIoRFJHLkRlZmluaXRpb24gPT0gIjAxNyAtIEFVVE9MT0dPVVMgQk9ORSBNQVJST1cgVFJBTlNQTEFOVCBXL08gQ0MvTUNDIikgJT4lIGRpc3RpbmN0KFByb3ZpZGVyLk5hbWUsIFRvdGFsLkRpc2NoYXJnZXMsIFByb3ZpZGVyLkNpdHksIFByb3ZpZGVyLlN0YXRlKQoKYGBgCgpXaGF0IHF1ZXN0aW9uIG1pZ2h0IHRoaXMgYW5hbHlzaXMgaGVscCB0byBhZGRyZXNzPwoKYGBge3IgZXZhbD1GQUxTRX0KV2hhdCBob3NwaXRhbHMgYXJlIHNwZWNpYWxpemVkIGhhdmUgdHJlYXRlZCBBVVRPTE9HT1VTIEJPTkUgTUFSUk9XIFRSQU5TUExBTlQgVy9PIENDL01DQy4KYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gQmUgc3VyZSB0byBhZGp1c3QgeW91ciBwbG90IGFib3ZlIHRvIHJlZmxlY3QgdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9Ck5vLiAKYGBgCgpXaGF0IGVsc2Ugd291bGQgd2UgbmVlZCB0byBrbm93IHRvIGZ1bGx5IGFkZHJlc3MgdGhpcyBxdWVzdGlvbj8gSGVyZSB5b3UgbWF5IGNvbnNpZGVyIHdoYXQgeW91IGtub3cgYWJvdXQgaG93IHRoaXMgZGF0YXNldCB3YXMgcHJvZHVjZWQgYW5kIGl0cyBsaW1pdGF0aW9ucy4KCmBgYHtyIGV2YWw9RkFMU0V9CkFnYWluLCB3ZSB3b3VsZCBuZWVkIHRvIGtlZXAgaW50byBjb25zaWRlcmF0aW9uIHRoZSBmYWN0IHRoYXQgdGhlc2UgcGF0aWVudHMgbWlnaHQgaGF2ZSBoYWQgb3RoZXIgY29uZGl0aW9ucyBhcyB3ZWxsLCBidXQgdGhpcyB3YXMgdGhlIHByaW1hcnkgZGlhZ25vc2lzIGFuZCB0cmVhdG1lbnQuIApgYGAKCldoYXQgaW5zaWdodCBjYW4geW91IGRyYXcgZnJvbSBydW5uaW5nIHRoaXMgZnVuY3Rpb24/CgpgYGB7ciBldmFsPUZBTFNFfQpJIGNvdWxkIHBvdGVudGlhbGx5IGRlZHVjdCB0aGF0IHRoZXNlIHR3byBob3NwaXRhbHMgYXJlIHNwZWNpYWxpemVkIGluIHRyZWF0aW5nIHRoaXMgY29uZGl0aW9uLCBhbHRob3VnaCBtb3JlIHJlc2VhcmNoIHNob3VsZCBiZSBkb25lIHRvIGZpbmQgb3V0IG1vcmUgYWJvdXQgdGhlIHR5cGUgb2YgcHJvY2VkdXJlcyBhbmQgdHJlYXRtZW50cyBhdmFpbGFibGUgYXQgb3RoZXIgaG9zcGl0YWxzIGFzIHdlbGwuICAKYGBgCgotLS0KCiMjIFZhcmlhdGlvbgoKVmFyaWF0aW9uIGlzIHRoZSBleHRlbnQgdG8gd2hpY2ggdGhlIHZhbHVlcyBpbiBhIHBhcnRpY3VsYXIgdmFyaWFibGUgdmFyeSBmcm9tIG9ic2VydmF0aW9uIHRvIG9ic2VydmF0aW9uLiBFeGFtaW5pbmcgdmFyaWF0aW9uIGludm9sdmVzIGxvb2tpbmcgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YWx1ZXMgaW4gYSBwYXJ0aWN1bGFyIGNvbHVtbiBpbiB0aGUgZGF0YXNldC4gRG8gd2UgaGF2ZSBhIHdob2xlIGJ1bmNoIG9mIG9uZSBwYXJ0aWN1bGFyIHZhbHVlIGluIGEgY2VydGFpbiB2YXJpYWJsZSwgYW5kIHZlcnkgZmV3IG9mIGFub3RoZXI/IE9yIG1heWJlLCBkbyB3ZSBoYXZlIGEgbW9yZSBldmVuIGRpc3RyaWJ1dGlvbiBvZiB2YWx1ZXMgYWNyb3NzIGEgdmFyaWFibGU/CgojIyMgZ2dwbG90CgpBdCB0aGlzIHBvaW50IGluIHRoZSBhc3NpZ25tZW50LCB3ZSB3aWxsIGJlZ2luIGxldmVyYWdpbmcgdGhlIFRpZHl2ZXJzZSBwYWNrYWdlICoqZ2dwbG90KiogdG8gY3JlYXRlIHBsb3RzIGZvciB2aXN1YWxpemluZyB0aGUgZGF0YS4gVG8gY3JlYXRlIGEgcGxvdCB3aXRoIGdncGxvdCwgd2Ugd2lsbCBmb2xsb3cgdGhpcyBiYXNpYyBmb3JtdWxhOgoKYGBge3IgZXZhbD1GQUxTRX0KZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IFZBUklBQkxFX05BTUUpKSArIAogIENIQVJUX1RZUEUKYGBgCgpGb3IgZXhhbXBsZSwgZm9yIGEgYmFyIGNoYXJ0LCB5b3Ugd2lsbCBjYWxsOgoKYGBge3IgZXZhbD1GQUxTRX0KZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IFZBUklBQkxFX05BTUUpKSArIAogIGdlb21fYmFyKCkKYGBgCgpGb3IgYSBjb2x1bW4gY2hhcnQsIHlvdSB3aWxsIGNhbGw6CgpgYGB7ciBldmFsPUZBTFNFfQpkZiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVkFSSUFCTEVfTkFNRSwgeSA9IFZBUklBQkxFX05BTUUpKSArIAogIGdlb21fY29sKCkKYGBgCiAgCkxldCdzIGJyZWFrIHRoYXQgZG93biBhIGJpdC4gRmlyc3QsIHlvdSB3aWxsIGNhbGwgeW91ciBkYXRhZnJhbWUuIEZvbGxvd2luZyB5b3VyIGRhdGFmcmFtZSBhbmQgYSBwaXBlLCB5b3Ugd2lsbCBjYWxsIGdncGxvdCgpLCB3aGljaCBiYXNpY2FsbHkgdGVsbHMgUiB0byBwcmVwYXJlIHRvIGNyZWF0ZSBhIHBsb3QuIEluc2lkZSBnZ3Bsb3QsIHlvdSB3aWxsIGxpc3QgKmFlc3RoZXRpY3MqLiBUaGVzZSBhcmUgdmFyaWFibGVzIGluIHRoZSBkYXRhc2V0IHRoYXQgeW91IHdvdWxkIGxpa2UgdG8gYXBwZWFyIG9uIHlvdXIgcGxvdC4gU2V0dGluZyB4ID0gVkFSSUFCTEVfTkFNRSB0ZWxscyBnZ3Bsb3QoKSB3aGF0IHZhcmlhYmxlIHRvIHBsb3Qgb24gdGhlIHgtYXhpcy4gU2V0dGluZyB5ID0gVkFSSUFCTEVfTkFNRSB0ZWxscyBnZ3Bsb3QoKSB3aGF0IHZhcmlhYmxlIHRvIHBsb3Qgb24gdGhlIHktYXhpcy4gRmluYWxseSwgZm9sbG93aW5nIGEgcGx1cyAoKykgc2lnbiwgeW91IHRlbGwgZ2dwbG90IHdoaWNoIHR5cGUgb2YgcGxvdCB0byBjcmVhdGUuIFRoZSBbZ2dwbG90IGNoZWF0c2hlZXRdKGh0dHBzOi8vcnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDMvZ2dwbG90Mi1jaGVhdHNoZWV0LnBkZikgbGlzdHMgYSBudW1iZXIgb2YgcGxvdHMgdGhhdCB5b3UgY2FuIGNyZWF0ZSB3aXRoIGdncGxvdCwgYXMgd2VsbCBhcyBhIG51bWJlciBvZiBkaWZmZXJlbnQgd2F5cyB0byBzdHlsZSB0aGUgcGxvdC4gV2Ugd2lsbCBwcmFjdGljZSBzZXZlcmFsIG9mIHRoZXNlIGJlbG93LiAKCkZvciBldmVyeSBwbG90IHRoYXQgeW91IHByb2R1Y2UsIEkgd2lsbCBleHBlY3QgeW91IHRvIGFkZCBhIHRpdGxlIGFuZCBsYWJlbHMgdG8gdGhlIHggYW5kIHkgYXhpcy4gWW91IGNhbiBkbyB0aGlzIGFzIGZvbGxvd3M6CgpgYGB7ciBldmFsPUZBTFNFfQpkZiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVkFSSUFCTEVfTkFNRSwgeSA9IFZBUklBQkxFX05BTUUpKSArIAogIGdlb21fY29sKCkgKwogIGxhYnModGl0bGUgPSAiRklMTCBUSVRMRSIsIHggPSAiRklMTCBYLUFYSVMgTEFCRUwiLCB5ID0gIkZJTEwgWS1BWElTIExBQkVMKQpgYGAKClRoZXJlIGFyZSBhbHNvIGEgbnVtYmVyIG9mIHVzZWZ1bCB0b29scyBmb3Igc3R5bGluZyB5b3VyIHBsb3RzLiBGb3IgaW5zdGFuY2Ugd2UgY2FuIHNldCB0aGUgdGhlbWUgb2YgdGhlIHBsb3QgdG8gbG9vayBhIGJpdCBtb3JlIHBvbGlzaGVkIGJ5IGFkZGluZyAiKyB0aGVtZV9idygpIiB0byB0aGUgcGxvdC4gSSB3aWxsIGRvIHRoaXMgZm9yIGFsbCBwbG90cyBpbiB0aGlzIGxhYi4KCmBgYHtyIGV2YWw9RkFMU0V9CmRmICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBWQVJJQUJMRV9OQU1FLCB5ID0gVkFSSUFCTEVfTkFNRSkpICsgCiAgZ2VvbV9jb2woKSArCiAgbGFicyh0aXRsZSA9ICJGSUxMIFRJVExFIiwgeCA9ICJGSUxMIFgtQVhJUyBMQUJFTCIsIHkgPSAiRklMTCBZLUFYSVMgTEFCRUwiKSArCiAgdGhlbWVfYncoKQpgYGAKClR3byBzdHlsaW5nIGlzc3VlcyB0aGF0IEknbSBzdXJlIHdpbGwgY29tZSB1cCBpbiBtb3N0IG9mIHlvdXIgcGxvdHMgaW5jbHVkZToKKiBjaGFuZ2luZyB4IG9yIHkgYXhpcyB0aWNrIG51bWJlcnMgZnJvbSBzY2llbnRpZmljIHRvIGNvbW1hIG5vdGF0aW9uOiArIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSBPUiArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKQoqIHR1cm5pbmcgeCBheGlzIHRpY2sgbWFya3MgOTAgZGVncmVlcyBzbyB0aGF0IHRoZXkgZG8gbm90IG92ZXJsYXA6ICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpIE9SICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpCgpgYGB7ciBldmFsPUZBTFNFfQpkZiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVkFSSUFCTEVfTkFNRSwgeSA9IFZBUklBQkxFX05BTUUpKSArIAogIGdlb21fY29sKCkgKwogIGxhYnModGl0bGUgPSAiRklMTCBUSVRMRSIsIHggPSAiRklMTCBYLUFYSVMgTEFCRUwiLCB5ID0gIkZJTEwgWS1BWElTIExBQkVMIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSArICNUdXJuIGxhYmVscyA5MCBkZWdyZWVzCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICNDaGFuZ2UgbGFiZWxzIGZyb20gc2NpZW50aWZpYyB0byBjb21tYSBub3RhdGlvbgpgYGAKClNvIGhvdyBkbyB3ZSB2aXN1YWxpemUgdmFyaWF0aW9uIHdpdGggZ2dwbG90PyBCZWxvdyBJIGRlc2NyaWJlIHR3byBkaWZmZXJlbnQgcGxvdHMgdGhhdCB5b3UgY2FuIGxldmVyYWdlIHRvIHZpc3VhbGl6ZSB2YXJpYXRpb24gLSBhIGJhciBwbG90IGFuZCBhIGZyZXF1ZW5jeSBwbG90LiAKCiMjIyBCYXIgUGxvdAoKQSAqYmFyIHBsb3QqIGRpc3BsYXlzIHRoZSBudW1iZXIgb2YgdGltZXMgZWFjaCB2YWx1ZSBhcHBlYXJzIGluIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUuIFRoaXMgd2lsbCB0ZWxsIHVzIGhvdyB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSBkYXRhc2V0ICp2YXJ5KiBpbiByZWdhcmRzIHRvIHRoYXQgdmFyaWFibGUuIEluIG90aGVyIHdvcmRzLCB0aGlzIHBsb3Qgd2lsbCBjb21tdW5pY2F0ZSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB5b3VyIGRhdGFzZXQgYnkgdGhhdCB2YXJpYWJsZS4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI1J1biB0aGlzIGNvZGUgY2h1bmsuCgojZGYgJT4lIGdncGxvdChhZXMoeCA9IENBVEVHT1JJQ0FMX1ZBUklBQkxFKSkgKyBnZW9tX2JhcigpICsgbGFicyh0aXRsZSA9ICJUSVRMRSIsIHggPSAiWC1BWElTIE5BTUUiLCB5ID0gIlktQVhJUyBOQU1FIikKCmhvc3BpdGFscyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyBieSBUeXBlIiwgeCA9ICJUeXBlIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArICNBZGRzIGEgdGl0bGUgdG8gdGhlIHBsb3QKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgI0NoYW5nZXMgeC1heGlzIHRpY2sgbGFiZWxzIDkwIGRlZ3JlZXMgCmBgYAoKUmVtZW1iZXIgdGhhdCB0aGlzIGRhdGFzZXQgaW5jbHVkZXMgaG9zcGl0YWxzIHRoYXQgYXJlIGRlc2lnbmF0ZWQgYXMgY2xvc2VkLiBEZXBlbmRpbmcgb24gdGhlIHF1ZXN0aW9uIHdlIGFyZSB0cnlpbmcgdG8gYWRkcmVzcywgd2UgbWF5IHdpc2ggdG8gem9vbSBpbiB0byBvbmx5IHRoZSBvYnNlcnZhdGlvbnMgc2lnbmlmeWluZyBhIGhvc3BpdGFsIHRoYXQgaXMgb3BlbiBiZWZvcmUgY3JlYXRpbmcgdGhpcyBwbG90LiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gQ0FURUdPUklDQUxfVkFSSUFCTEUpKSArIGdlb21fYmFyKCkgKyBsYWJzKHRpdGxlID0gIlRJVExFIiwgeCA9ICJYLUFYSVMgTkFNRSIsIHkgPSAiWS1BWElTIE5BTUUiKQoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIpICsgI0FkZHMgYSB0aXRsZSB0byB0aGUgcGxvdAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAjQ2hhbmdlcyB4LWF4aXMgdGljayBsYWJlbHMgOTAgZGVncmVlcyAKYGBgCgojIyMjIFRpdGxpbmcgYSBCYXIgUGxvdAoKTm90ZSBob3cgSSB0aXRsZWQgbXkgZmlyc3QgcGxvdCBhYm92ZTogIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIGJ5IFR5cGUiIFJlbWVtYmVyIGxhc3Qgd2Vlaywgd2hlbiB3ZSBpZGVudGlmaWVkIHdoYXQgbWFrZXMgZWFjaCBvYnNlcnZhdGlvbiBpbiBvdXIgZGF0YXNldCB1bmlxdWU/IEhlcmUgSSBhbSBjb3VudGluZyB0aGUgb2JzZXJ2YXRpb25zIGJ5IFR5cGUsIGFuZCBpbiBvcmRlciB0byBrbm93IHdoYXQgSSdtIGNvdW50aW5nLCBJIG5lZWQgdG8ga25vdyB3aGF0IGVhY2ggb2JzZXJ2YXRpb24gcmVmZXJzIHRvLiBBIGdvb2QgZm9ybXVsYSBmb3IgdGl0bGluZyBiYXIgcGxvdHMgaXMgYXMgZm9sbG93czoKCk51bWJlciBvZiBfX19fXyBieSBbeC1heGlzIHZhcmlhYmxlIG5hbWVdCgpJbiBvcmRlciB0byBmaWxsIGluIHRoZSBibGFuayBsaW5lIGFib3ZlLCBjb25zaWRlciB0aGUgc3RhdGVtZW50IHdlIHByb2R1Y2VkIGxhc3Qgd2VlazogIkkgaGF2ZSBucm93KGRmKSB1bmlxdWUgX19fX18gcmVwcmVzZW50ZWQgaW4gbXkgZGF0YXNldC4iIFRoYXQgYmxhbmsgbGluZSB0b2xkIHVzIHdoYXQgZWFjaCBvYnNlcnZhdGlvbiBpbiB0aGUgZGF0YXNldCByZXByZXNlbnRlZCAtIG9yIGl0cyAqb2JzZXJ2YXRpb25hbCB1bml0Ki4gSG93ZXZlciB3ZSBmaWxsZWQgaW4gdGhhdCBibGFuayBsaW5lIHNob3VsZCBhbHNvIGJlIGhvdyB3ZSBmaWxsIGluIHRoZSB0aXRsZSBvZiBhIGJhciBwbG90LiAKClRoZSBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIHNob3VsZCBiZSB5b3VyIHgtbGFiZWwgYW5kICJDb3VudCBvZiBfX19fX18iIChmaWxsZWQgdGhlIHNhbWUgYXMgYWJvdmUpIHNob3VsZCBiZSB5b3VyIHktbGFiZWwuIE5vdGUgdGhhdCBpZiB5b3UgZmlsdGVyIHlvdXIgZGF0YXNldCwgeW91IHNob3VsZCBhY2NvdW50IGZvciB0aGlzIGluIHRoZSB0aXRsZTogIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIGJ5IFR5cGUiCgojIyMjIyBXaGF0IGlmIEkgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24/CgpXaGVuIHdlIGNyZWF0ZSBhIGJhciBwbG90LCB3ZSBhcmUgY291bnRpbmcgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgdGhhdCBmYWxsIGludG8gZWFjaCBjYXRlZ29yeS4gSWYgdGhlcmUgaXMgb25seSBvbmUgdmFyaWFibGUgdGhhdCBtYWtlcyB1cCB5b3VyIHVuaXF1ZSBrZXksIHRoYXQgb25lIHZhcmlhYmxlIHdpbGwgcmVwcmVzZW50IHdoYXQgaXMgYmVpbmcgY291bnRlZCAoZS5nLiBhYm92ZSB3ZSBhcmUgY291bnRpbmcgaG9zcGl0YWxzIGJ5IGNhdGVnb3J5KS4gSG93ZXZlciwgaWYgdGhlcmUgYXJlIG11bHRpcGxlIHZhcmlhYmxlcyBpbiB5b3VyIHVuaXF1ZSBrZXksIHRoZW4gaWRlbnRpZnlpbmcgd2hhdCBpdCBpcyB0aGF0IHlvdSBhcmUgY291bnRpbmcgYmVjb21lcyBhIGxpdHRsZSBtb3JlIGNvbXBsaWNhdGVkLiBGb3IgaW5zdGFuY2UsIGxldCdzIHNheSB5b3VyIGRhdGEgcmVwb3J0cyB0aGUgcG9wdWxhdGlvbiBvZiBlYWNoIGNvdW50cnkgZWFjaCB5ZWFyIGFzIGl0IGRvZXMgaW4gdGhlIHdvcmxkX2hlYWx0aF9lY29uIGRhdGFzZXQuIE5vdyBsZXQncyBzYXkgdGhhdCB5b3Ugd2FudGVkIHRvIHBsb3QgdGhlIG51bWJlciBvZiBjb3VudHJpZXMgcGVyIGNvbnRpbmVudC4gSWYgeW91IHdlcmUgdG8gY2FsbDoKCmBgYHtyfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCndvcmxkX2hlYWx0aF9lY29uICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjb250aW5lbnQpKSArIAogIGdlb21fYmFyKCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIENvdW50cmllcyBwZXIgQ29udGluZW50IC0gSW5jb3JyZWN0IiwgeCA9ICJDb250aW5lbnQiLCB5ID0gIkNvdW50IG9mIENvdW50cmllcyIpICsgI0FkZHMgYSB0aXRsZSB0byB0aGUgcGxvdAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAjQ2hhbmdlcyB4LWF4aXMgdGljayBsYWJlbHMgOTAgZGVncmVlcyAKYGBgCgouLi4geW91IHdvdWxkIGJlIGNvdW50aW5nIHRoZSBjb21iaW5hdGlvbiBvZiB0aGUgbnVtYmVyIG9mIGNvdW50cmllcyBhbmQgeWVhcnMgcGVyIGNvbnRpbmVudC4gVGhlcmUgYXJlIG5vdCA4MDAgY291bnRyaWVzIGluIEFmcmljYSwgYnV0IEFmcmljYSBhcHBlYXJzIGluIHRoZSBkYXRhc2V0IDgwMCB0aW1lcyBiZWNhdXNlIGVhY2ggY291bnRyeSBpbiBBZnJpY2EgaGFzIHNldmVyYWwgcm93cyBpbiB0aGUgZGF0YXNldCAtIG9uZSBmb3IgZWFjaCByZXBvcnRpbmcgeWVhci4gSW4gb3RoZXIgd29yZHMsIGVhY2ggY291bnRyeSBpcyByZXByZXNlbnRlZCBpbiB0aGUgYmFyIGZvciBldmVyeSB5ZWFyIHRoYXQgaXQgd2FzIGluY2x1ZGVkIGluIHRoZSBkYXRhc2V0LiBUaGUgeS1heGlzIGRvZXMgbm90IGp1c3QgcmVwcmVzZW50IGNvdW50cmllcyBidXQgYm90aCBjb3VudHJpZXMgYW5kIHllYXJzLiBJZiB3ZSB3YW50IHRoZSB5LWF4aXMgdG8gb25seSBiZSBjb3VudGluZyBvbmUgdGhpbmcsIHRoZW4gd2UgbmVlZCB0byBmaXJzdCByZWR1Y2UgdGhlIGRhdGFzZXQgdG8gdmFsdWVzIGluIGEgcGFydGljdWxhciBjb250ZXh0LiBZb3UgY2FuIGRvIHRoaXMgYnkgZmlsdGVyaW5nIHRoZSBkYXRhIGFzIHlvdSBoYWQgYmVlbiBkb2luZyBhYm92ZS4KCmBgYHtyfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCndvcmxkX2hlYWx0aF9lY29uICU+JSAKICBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhciwgbmEucm0gPSBUUlVFKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29udGluZW50KSkgKyAKICBnZW9tX2JhcigpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBDb3VudHJpZXMgcGVyIENvbnRpbmVudCBpbiB0aGUgbW9zdCBSZWNlbnQgUmVwb3J0aW5nIFllYXIiLCB4ID0gIkNvbnRpbmVudCIsIHkgPSAiQ291bnQgb2YgQ291bnRyaWVzIikgKyAjQWRkcyBhIHRpdGxlIHRvIHRoZSBwbG90CiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpICNDaGFuZ2VzIHgtYXhpcyB0aWNrIGxhYmVscyA5MCBkZWdyZWVzCmBgYAoKPiBOb3RlIHRoZSBhZGRpdGlvbiB0byBteSB0aXRsZSBhYm92ZS4gSWYgeW91IGZpbHRlciB5b3VyIGRhdGFzZXQsIHRoZSBmb3JtdWxhIGZvciB0aXRsaW5nIGNoYW5nZXMgYSBiaXQgdG8gRnJlcXVlbmN5IG9mIF9fX19fIGFjcm9zcyBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIGluIFtmaWx0ZXJlZCB2YWx1ZV0KCiMjIyMgU2VsZWN0IGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgZm9yIHdoaWNoIHlvdSB3YW50IHRvIHZpc3VhbGl6ZSB0aGUgZnJlcXVlbmN5IG9mIHRpbWVzIGl0IGFwcGVhcnMgaW4gdGhlIGRhdGFzZXQuIAoKSSByZWNvbW1lbmQgdGhhdCB5b3Ugc2VsZWN0IG9uZSBvZiB0aGUgc2FtZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgdGhhdCB5b3UgYW5hbHl6ZWQgd2l0aCB0aGUgZGlzdGluY3QoKSBmdW5jdGlvbiBsYXN0IHdlZWsuIElmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbiwgYmUgc3VyZSB0byBmaWx0ZXIgeW91ciBkYXRhIGZpcnN0IHNvIHRoYXQgYWxsIG9mIHRoZSBvYnNlcnZhdGlvbnMgeW91IGFyZSBjb3VudGluZyBoYXZlIG9uZSB2YXJpYWJsZXMgYXMgYSB1bmlxdWUga2V5LiBJZiB5b3Ugbm90aWNlIHN0eWxpbmcgaXNzdWVzIHdpdGggeW91ciBkYXRhLCBiZSBzdXJlIHRvIGNvbnNpZGVyIG15IG5vdGVzIGFib3V0IGhvdyB0byBmaXggdGhlbSBhYm92ZS4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojVW5jb21tZW50IHRoZSBsaW5lIGJlbG93IGFuZCBmaWxsIGFwcHJvcHJpYXRlbHkuIEFkZCBhIHRpdGxlIGFuZCBsYWJlbHMgdG8geW91ciBwbG90cywgYW5kIGFkanVzdCBpdHMgc3R5bGUgdG8gYmUgbGVnaWJsZS4gVGhlbiBydW4gdGhlIGNvZGUuCiNfX19fXyAlPiUgZ2dwbG90KGFlcyh4ID0gX19fX18pKSArIGdlb21fYmFyKCkKCiNJZiBxdWFsaWZpZWQ6CmlwcHMgJT4lIGZpbHRlcihEUkcuRGVmaW5pdGlvbiA9PSAiMzEzIC0gQ0hFU1QgUEFJTiIpICU+JSBnZ3Bsb3QoYWVzKHggPSBQcm92aWRlci5TdGF0ZSkpICsgZ2VvbV9iYXIoKSArCmxhYnModGl0bGUgPSAiTnVtYmVyIG9mIENoZXN0IFBhaW4gRGlhZ25vc2VzIGFjcm9zcyBIb3NwaXRhbHMgYnkgU3RhdGUiLCB4ID0gIlN0YXRlIiwgeSA9ICJDb3VudCBvZiBDaGVzdCBQYWluIERpYWdub3NlcyIpICsKdGhlbWVfYncoKQpgYGAKClJlZmxlY3Qgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiBjYXRlZ29yaWVzIGluIHRoZSBkYXRhc2V0LiBJcyB0aGVyZSBhbiBldmVuIGRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZhdGlvbnMgYWNyb3NzIGVhY2ggY2F0ZWdvcnksIG9yIGFyZSBjZXJ0YWluIGNhdGVnb3JpZXMgbW9yZSByZXByZXNlbnRlZCB0aGFuIG90aGVycz8gV2h5IG1pZ2h0IHRoaXMgYmU/IFdoYXQgZG9lcyB0aGlzIHNheSBhYm91dCB0aGUgc29jaWFsLCBwb2xpdGljYWwsIG9yIGVjb25vbWljIGxhbmRzY2FwZSBvZiB5b3VyIHRvcGljPyAKCmBgYHtyIGV2YWw9RkFMU0V9Ck5vLCB0aGVyZSBpcyBub3QgYW4gZXZlbiBkaXN0cmlidXRpb24gb2Ygb2JzZXJ2YXRpb25zIGFjcm9zcyBTdGF0ZXMuIEFzIGl0IGNhbiBiZSBzZWVuIGZyb20gdGhlIGdyYXBoIHRoZXJlIGFyZSBzb21lIFN0YXRlcyB0aGF0IGhhdmUgYSBzaWduaWZpY2FudGx5IGxhcmdlciBudW1iZXIgb2YgcGF0aWVudHMgZGlhZ25vc2VkIGFuZCB0cmVhdGVkIGZvciBjaGVzdCBwYWluLiBPbmUgb2YgdGhlIHJlYXNvbnMgd2h5IGlzIHRoYXQgc29tZSBTdGF0ZXMgaGF2ZSBoaWdoZXIgbnVtYmVyIG9mIHBlb3BsZSB0aGF0IGFyZSBpbiBNZWRpY2FyZS4KYGBgCgpSZWZsZWN0IG9uIHdoYXQgeW91IGxlYXJuZWQgYWJvdXQgdGhlIGhpc3Rvcnkgb2YgdGhlIGNhdGVnb3JpZXMgeW91IHBsb3R0ZWQgYWJvdmUgaW4gbGFzdCB3ZWVrJ3MgbGFiLiBIb3cgaGF2ZSB0aGUgc29jaWFsLCBwb2xpdGljYWwsIGFuZCBlY29ub21pYyBmb3JjZXMgc2hhcGluZyB0aGlzIGNhdGVnb3JpemF0aW9uIGltcGFjdGVkIGhvdyB3ZSBjb3VudCBvYnNlcnZhdGlvbnMgcmVsYXRlZCB0byB0aGlzIHRvcGljPyBIb3cgbWlnaHQgdGhpcyBwbG90IGxvb2sgZGlmZmVyZW50IGlmIHRoaXMgdmFyaWFibGUgaGFkIGJlZW4gY2F0ZWdvcml6ZWQgaW4gYSBkaWZmZXJlbnQgd2F5PwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCByZXNwb25zZSBoZXJlLiAKYGBgCgojIyMgRnJlcXVlbmN5IFBsb3QKCkEgKmZyZXF1ZW5jeSBwbG90KiB3aWxsIGRpc3BsYXkgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YWx1ZXMgaW4gYSBudW1lcmljIHZhcmlhYmxlIHdpdGhpbiBhIGRlc2lnbmF0ZWQgc2V0IG9mIGluY3JlbWVudHMuIFRoaXMgd2lsbCB0ZWxsIHVzIGhvdyB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSBkYXRhc2V0ICp2YXJ5KiBpbiByZWdhcmRzIHRvIHRoYXQgdmFyaWFibGUuIEluIG90aGVyIHdvcmRzLCB0aGlzIHBsb3Qgd2lsbCBjb21tdW5pY2F0ZSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB5b3VyIGRhdGFzZXQgYnJva2VuIGRvd24gaW50byBpbmNyZW1lbnRzIG9mIHRoZSB2YWx1ZXMgaW4gdGhhdCB2YXJpYWJsZS4gCgpDb25zaWRlciB0aGUgcGxvdCBiZWxvdy4gVGhpcyBwbG90IHRlbGxzIHVzIHRoZSBkaXN0cmlidXRpb24gb2YgYmVkcyBhY3Jvc3Mgb3BlbiBob3NwaXRhbHMuIEl0IHRlbGxzIHVzIGhvdyBtYW55IGhvc3BpdGFscyB0aGVyZSBhcmUgaW4gZWFjaCBpbmNyZW1lbnQgb2YgMTAgYmVkcy4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gTlVNRVJJQ19WQVJJQUJMRSkpICsgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEpICsgbGFicyh0aXRsZSA9ICJUSVRMRSIsIHggPSAiWC1BWElTIE5BTUUiLCB5ID0gIlktQVhJUyBOQU1FIikKCmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogIGdncGxvdChhZXMoeCA9IEJFRFMpKSArCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQmVkcyBhY3Jvc3MgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIiwgeCA9ICJCZWRzIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArCiAgdGhlbWVfYncoKQpgYGAKCk5vdGUgdGhhdCBiaW53aWR0aCByZWZlcnMgdG8gdGhlIHNpemUgb2YgdGhlIGluY3JlbWVudHMgYXQgd2hpY2ggZnJlcXVlbmN5IHdpbGwgYmUgY2FsY3VsYXRlZC4gQWJvdmUgdGhlIGJpbndpZHRoIGlzIHNldCB0byAxMC4gVGhpcyBtZWFucyB0aGF0IGdncGxvdCB3aWxsIGRpc3BsYXkgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIHZhbHVlIGF0IGludGVydmFscyBvZiAxMCwgMjAsIDMwLCA0MCwgZXRjLiBXaGVuIHdlIHNldCB0aGUgYmluZHdpZHRoIHRvIDEsIGdncGxvdCB3aWxsIGRpc3BsYXkgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIHZhbHVlIGF0IGludGVydmFscyBvZiAxLCAyLCAzLCA0LiBldGMuIFdoYXQgZGlmZmVyZW5jZSBkb2VzIHRoaXMgbWFrZT8gCgpOb3RpY2Ugd2hhdCBoYXBwZW5zIHdoZW4gd2Ugc2V0IHRoZSBiaW53aWR0aCB0byAxLiBXaGlsZSBhYm92ZSB3ZSBjb3VudCB0aGUgbnVtYmVyIG9mIGhvc3BpdGFscyB3aXRoIDAtMTAgYmVkcyAgMTAtMjAgYmVkcywgMjAtMzAgYmVkcywgZXRjLCB0aGlzIHdpbGwgY291bnQgdGhlIG51bWJlciBvZiBob3NwaXRhbHMgd2l0aCAwLTEgYmVkcywgMS0yIGJlZHMsIDItMyBiZWRzLCBhbmQgc28gb24uIEJlY2F1c2Ugd2UgYXJlIGNvdW50aW5nIHRoZSBudW1iZXIgaW4gc3VjaCBzbWFsbCBpbmNyZW1lbnRzLCB0aGUgcGxvdCB3aWxsIGxvb2sgbXVjaCBtb3JlIGphZ2dlZCBhbmQgd2lsbCB0YWtlIGEgbG9uZ2VyIHRpbWUgdG8gbG9hZC4gVGhpcyBwbG90IGRpc3BsYXlzIHRoZSBjb3VudHMgaW4gKmZpbmVyKiBncmFudWxhcml0eSB0aGFuIHRoZSBmaXJzdCBwbG90LgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gQkVEUykpICsKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMSkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiIsIHggPSAiQmVkcyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKwogIHRoZW1lX2J3KCkKYGBgCgpXaGVuIHdlIHNldCB0aGUgYmlud2lkdGggdG8gMTAwLCB3ZSBjb3VudCB0aGUgbnVtYmVyIG9mIGhvc3BpdGFscyB3aXRoIDAtMTAwIGJlZHMsIDEwMC0yMDAgYmVkcywgMjAwLTMwMCBiZWRzLCBhbmQgc28gb24uIEJlY2F1c2Ugd2UgYXJlIGNvdW50aW5nIHRoZSBudW1iZXIgaW4gbGFyZ2VyIGluY3JlbWVudHMsIHRoZSBwbG90IHdpbGwgbG9vayBtdWNoIHNtb290aGVyIGFuZCB3aWxsIHRha2UgbGVzcyB0aW1lIHRvIGxvYWQuIFRoaXMgcGxvdCBkaXNwbGF5cyB0aGUgY291bnRzIGluICp0aGlja2VyKiBncmFudWxhcml0eSB0aGFuIHRoZSBmaXJzdCBwbG90LgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gQkVEUykpICsKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMTAwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQmVkcyBhY3Jvc3MgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIiwgeCA9ICJCZWRzIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyMgVGl0bGluZyBhIEZyZXF1ZW5jeSBQbG90CgpOb3RlIGhvdyBJIHRpdGxlZCBteSBwbG90IGFib3ZlOiAiRGlzdHJpYnV0aW9uIG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiIgQ29uc2lkZXIgYWdhaW4gd2hhdCBtYWtlcyBlYWNoIG9ic2VydmF0aW9uIHVuaXF1ZS4gQSBnb29kIGZvcm11bGEgZm9yIHRpdGxpbmcgZnJlcXVlbmN5IHBsb3RzIGlzIGFzIGZvbGxvd3M6CgpGcmVxdWVuY3kgb2YgW3gtYXhpcyB2YXJpYWJsZSBuYW1lXSBhY3Jvc3MgX19fX18gCgpBZ2Fpbiwgd2UgY2FuIGZpbGwgaW4gdGhlIGJsYW5rIHdpdGggb3VyIG9ic2VydmF0aW9uYWwgdW5pdC4gVGhlIFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gc2hvdWxkIGJlIHlvdXIgeC1sYWJlbCBhbmQgIkNvdW50IG9mIF9fX19fXyIgKGZpbGxlZCB0aGUgc2FtZSBhcyBhYm92ZSkgc2hvdWxkIGJlIHlvdXIgeS1sYWJlbC4KCiMjIyMgV2hhdCBpZiBJIGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uPwoKTGV0J3MgdGFsayBhYm91dCB3aGF0IHdvdWxkIGhhcHBlbiBpZiBJIHdlcmUgdG8gbWFrZSBhIGZyZXF1ZW5jeSBwbG90IG9mIHRoZSBUb3RhbC5DYXNlcyBpbiB0aGUgY2FzZXMgZGF0YXNldDoKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCmNhc2VzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBUb3RhbC5DYXNlcykpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwMDAwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQ2FzZXMgYWNyb3NzIF9fX18iLCB4ID0gIlRvdGFsIENhc2VzIiwgeSA9ICJDb3VudCBvZiBfX19fXyIpICsgIyBUbyBhZGQgdGl0bGVzIGFuZCBsYWJlbHMKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgKyAjVHVybiBsYWJlbHMgOTAgZGVncmVlcwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSAjQ2hhbmdlIGxhYmVscyBmcm9tIHNjaWVudGlmaWMgdG8gY29tbWEgbm90YXRpb24KYGBgCgpXZSBrbm93IHRoYXQgZWFjaCBvYnNlcnZhdGlvbiBpbiB0aGUgY2FzZXMgZGF0YXNldCByZWZlcnMgdG8gYSBwcm92aW5jZS9jb3VudHJ5IHBhaXIuIFNvIGhlcmUgSSdtIGNvdW50aW5nIHRoZSBudW1iZXIgb2YgcHJvdmluY2UvY291bnRyaWVzIGluIGVhY2ggYnJhY2tldCBvZiB0b3RhbCBjYXNlcy4gU2luY2Ugb25seSBzb21lIGNvdW50cmllcyBpbiB0aGlzIGRhdGFzZXQgYXJlIGJyb2tlbiBpbnRvIHByb3ZpbmNlcywgd2UgYXJlIGNvbXBhcmluZyBjb3VudHMgb2YgY2FzZXMgYWNyb3NzIGRpZmZlcmVudCBnZW9ncmFwaGljIHNjYWxlcyAtIHNvbWV0aW1lcyBhdCB0aGUgcHJvdmluY2UgbGV2ZWwgYW5kIHNvbWV0aW1lcyBhdCB0aGUgY291bnRyeSBsZXZlbC4gSW4gdGhpcyBjYXNlLCBpdCBtYWtlcyBtb3JlIHNlbnNlIHRvIHRvdGFsIHVwIHRoZSBudW1iZXIgb2YgY2FzZXMgcGVyIGNvdW50cnkgYW5kIHRoZW4gcGxvdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNhc2VzIGFjcm9zcyBjb3VudHJpZXMuIFdlIGNhbiB1c2UgZ3JvdXBfYnkoKSBhbmQgc3VtbWFyaXplKCkgdG8gZG8gdGhpczoKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCmNhc2VzICU+JSAKICBncm91cF9ieShDb3VudHJ5LlJlZ2lvbikgJT4lCiAgc3VtbWFyaXplKFRvdGFsLkNhc2VzID0gc3VtKFRvdGFsLkNhc2VzLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVG90YWwuQ2FzZXMpKSArIAogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxMDAwMDApICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDYXNlcyBhY3Jvc3MgQ291bnRyaWVzIiwgeCA9ICJUb3RhbCBDYXNlcyIsIHkgPSAiQ291bnQgb2YgQ291bnRyaWVzIikgKyAjIFRvIGFkZCB0aXRsZXMgYW5kIGxhYmVscwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSArICNUdXJuIGxhYmVscyA5MCBkZWdyZWVzCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICNDaGFuZ2UgbGFiZWxzIGZyb20gc2NpZW50aWZpYyB0byBjb21tYSBub3RhdGlvbgpgYGAKCldoYXQgYWJvdXQgdGhlIHdvcmxkX2hlYWx0aF9lY29uIGRhdGE/IFdpdGhvdXQgc2VwYXJhdGluZyBvdXQgdGhlc2UgdW5pdHMgb2Ygb2JzZXJ2YXRpb24sIHdlIHdvdWxkIGJlIHZpc3VhbGl6aW5nIG11bHRpcGxlIHZhbHVlcyByZXBvcnRlZCBhdCB0aGUgc2FtZSBwbGFjZSBhdCBkaWZmZXJlbnQgcGVyaW9kcyBpbiB0aW1lIChpLmUuIGV2ZXJ5IHllYXIgc2luY2UgMTk5NSkuIEluc3RlYWQsIHdlIHdhbnQgdG8gem9vbSBpbnRvIGEgc2luZ2xlIHllYXIgaW4gdGhlIGRhdGFzZXQgc28gd2UgYXJlIGp1c3QgY29tcGFyaW5nIHZhbHVlcyBhY3Jvc3MgcGxhY2UuIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKd29ybGRfaGVhbHRoX2Vjb24gJT4lIAogIGZpbHRlcih5ZWFyID09IG1heCh5ZWFyLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0b3RfaGVhbHRoX3NwX3BwKSkgKyAKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMTAwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgVG90YWwgSGVhbHRoIFNwZW5kaW5nIHBlciBQZXJzb24gYWNyb3NzIENvdW50cmllcyBpbiAyMDEwIiwgeCA9ICJUb3RhbCBIZWFsdGggU3BlbmRpbmcgcGVyIFBlcnNvbiIsIHkgPSAiQ291bnQgb2YgQ291bnRyaWVzIikgKyAjIFRvIGFkZCB0aXRsZXMgYW5kIGxhYmVscwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSArICNUdXJuIGxhYmVscyA5MCBkZWdyZWVzCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICNDaGFuZ2UgbGFiZWxzIGZyb20gc2NpZW50aWZpYyB0byBjb21tYSBub3RhdGlvbgpgYGAKCj4gTm90ZSB0aGUgYWRkaXRpb24gdG8gbXkgdGl0bGUgYWJvdmUuIElmIHlvdSBmaWx0ZXIgeW91ciBkYXRhc2V0LCB0aGUgZm9ybXVsYSBmb3IgdGl0bGluZyBjaGFuZ2VzIGEgYml0IHRvIEZyZXF1ZW5jeSBvZiBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIGFjcm9zcyBfX19fXyBpbiBbZmlsdGVyZWQgdmFsdWVdCgojIyMjIFNlbGVjdCBhIG51bWVyaWMgdmFyaWFibGUgZm9yIHdoaWNoIHlvdSB3YW50IHRvIHZpc3VhbGl6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIGEgc2V0IG9mIHZhbHVlcy4gCgpCZSBzdXJlIHRvIHNlbGVjdCBhIHZhcmlhYmxlIHRoYXQgZGVzY3JpYmVzIHNvbWV0aGluZyBhYm91dCB0aGUgb2JzZXJ2YXRpb25hbCB1bml0IGFuZCBub3QgYW5vdGhlciBjYXRlZ29yaWNhbCB2YXJpYWJsZSBpbiB5b3VyIGRhdGFzZXQuIEZvciBpbnN0YW5jZSwgbGV0J3Mgc2F5IHlvdSBoYWQgdGhlIGZvbGxvd2luZyBkYXRhIHRhYmxlIC0gd2l0aCBlYWNoIHJvdyByZXBvcnRpbmcgYW4gZW52aXJvbm1lbnRhbCB2aW9sYXRpb24gYXQgYSBmYWNpbGl0eToKClZpb2xhdGlvbiBOdW1iZXIgfCBGYWNpbGl0eSBOYW1lIHwgRmFjaWxpdHkgVG93biB8IFBvcHVsYXRpb24gb2YgRmFjaWxpdHkgVG93bgpfX19fX19fX19fX19fX19fXyB8IF9fX19fX19fX19fX19fX19fIHwgX19fX19fX19fX19fX19fX18gfCBfX19fX19fX19fX19fX19fXyAKMTIzNDU2NyB8IEZhY2lsaXR5IEEgfCBUYXJyeXRvd24gfCA5MDAwMAoyMzQ1Njc4IHwgRmFjaWxpdHkgQiB8IFRhcnJ5dG93biB8IDkwMDAwCjM0NTY3ODkgfCBGYWNpbGl0eSBDIHwgQW5vdGhlciBUb3duIHwgNzAwMDAKCkluIHRoaXMgdGFibGUsIHdlIHdvdWxkIG5vdCB3YW50IHRvIGNyZWF0ZSBhIGZyZXF1ZW5jeSBwbG90IHdpdGggcG9wdWxhdGlvbiBvZiBmYWNpbGl0eSB0b3duLiBUaGlzIGlzIGJlY2F1c2Ugb3VyIG9ic2VydmF0aW9uYWwgdW5pdCBpcyBhIHZpb2xhdGlvbiwgbm90IGEgdG93biwgYW5kIHBvcHVsYXRpb24gZG9lcyBub3QgZGVzY3JpYmUgc29tZXRoaW5nIGFib3V0IHRoZSB2aW9sYXRpb24gYnV0IGluc3RlYWQgZGVzY3JpYmVzIHNvbWV0aGluZyBhYm91dCB0aGUgdG93biB0aGUgZmFjaWxpdHkgaXMgaW4uIElmIHdlIHdlcmUgdG8gY3JlYXRlIGEgZnJlcXVlbmN5IHBsb3Qgd2l0aCB0aGlzIHZhcmlhYmxlLCB3ZSB3b3VsZCBiZSBjb3VudGluZyB0aGUgbnVtYmVyIG9mIHRpbWVzIGVhY2ggcG9wdWxhdGlvbiB2YWx1ZSBhcHBlYXJzIGluIHRoZSBkYXRhc2V0IC0gc29tZXRoaW5nIHRoYXQgZG9lcyBub3QgbWFrZSBtdWNoIHNlbnNlLCBzaW5jZSB3ZSBjYW4gaGF2ZSB0aGUgc2FtZSB0b3duJ3MgcG9wdWxhdGlvbiB0b3duIGFwcGVhciBzZXZlcmFsIHRpbWVzIGluIHRoZSBkYXRhc2V0IGlmIHRoZXJlIGFyZSBtb3JlIHRoYW4gb25lIHZpb2xhdGlvbnMgb3IgbW9yZSB0aGFuIG9uZSBmYWNpbGl0aWVzIGluIGEgdG93bi4gTm9uZSBvZiB5b3Ugc2hvdWxkIGhhdmUgdG8gd29ycnkgYWJvdXQgdGhpcyBpbiB5b3VyIGRhdGFzZXRzLiBBbGwgb2YgeW91ciBtZWFzdXJlcyBkZXNjcmliZSB0aGUgb2JzZXJ2YXRpb25hbCB1bml0LgoKSWYgeW91IGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uLCBiZSBzdXJlIHRvIGZpcnN0IHpvb20gaW50byBhIHNldCBvZiBvYnNlcnZhdGlvbnMgaW4geW91ciBkYXRhICh1c2luZyBmaWx0ZXIoKSkuCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI1VuY29tbWVudCB0aGUgbGluZSBiZWxvdyBhbmQgZmlsbCBhcHByb3ByaWF0ZWx5LiBBZGQgYSB0aXRsZSBhbmQgbGFiZWxzIHRvIHlvdXIgcGxvdHMuIFJ1biB0aGUgY29kZS4KaXBwcyAlPiUgZmlsdGVyKERSRy5EZWZpbml0aW9uID09ICIzMTMgLSBDSEVTVCBQQUlOIikgJT4lIGdncGxvdChhZXMoeCA9IFRvdGFsLkRpc2NoYXJnZXMpKSAgKyBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMTApIApgYGAKClRoaXMgZ2l2ZXMgdXMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQuIFJlZmxlY3Qgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YWx1ZXMuIFdoYXQgYXJlIHRoZSByYW5nZSBvZiB2YWx1ZXMgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGE/IEFyZSB0aGUgdmFsdWVzIGV2ZW5seSBkaXN0cmlidXRlZCwgb3IgYXJlIGNlcnRhaW4gdmFsdWVzIG1vcmUgcmVwcmVzZW50ZWQgdGhhbiBvdGhlcnM/IFdoeSBtaWdodCB0aGlzIGJlPyBEbyBhbnkgb2YgdGhlIHZhbHVlcyBzdXJwcmlzZSB5b3U/IFdoeT8gCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoeSBkaWQgeW91IHNlbGVjdCB0aGUgYmlud2lkdGggdGhhdCB5b3UgZGlkPyBIb3cgbWlnaHQgdGhlIHN0b3J5IHlvdXIgcGxvdCB0ZWxscyBjaGFuZ2UgaWYgeW91IHdlcmUgdG8gY2hhbmdlIHRoZSBiaW53aWR0aD8gV2hhdCBhbm9tYWxpZXMgbWlnaHQgYmUgaGlkZGVuIHdpdGggYSBsYXJnZXIgYmlud2lkdGgsIGFuZCB3aGF0IHRyZW5kcyBtaWdodCBiZSBoaWRkZW4gd2l0aCBhIHNtYWxsZXIgYmlud2lkdGg/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHJlc3BvbnNlIGhlcmUuIApgYGAKCkNoZWNrIGhvdyB0aGUgbnVtZXJpYyB2YXJpYWJsZSB3YXMgZGVmaW5lZCBpbiB0aGUgZGF0YSBkaWN0aW9uYXJ5LCBhbmQgcXVvdGUgdGhlIGRlZmluaXRpb24gYmVsb3cuIEhvdyBtaWdodCB0aGUgY291bnRzIHJlcHJlc2VudGVkIGluIHlvdXIgZnJlcXVlbmN5IHBsb3QgYXBwZWFyIGRpZmZlcmVudGx5IGlmIHRoaXMgdmFyaWFibGUgd2FzIGRlZmluZWQgZGlmZmVyZW50bHk/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHJlc3BvbnNlIGhlcmUuIApgYGAKCiMjIENvLXZhcmlhdGlvbgoKQ28tdmFyaWF0aW9uIGlzIHRoZSBleHRlbnQgdG8gd2hpY2ggdGhlIHZhbHVlcyB0aGF0IGNvbnN0aXR1dGUgdHdvIG9yIG1vcmUgdmFyaWFibGVzIHZhcnkgaW4gcmVsYXRpb24gdG8gb25lIGFub3RoZXIuIFRvIHZpc3VhbGl6ZSBjby12YXJpYXRpb24sIHdlIG1pZ2h0IGNyZWF0ZToKCiMjIyBDb3VudCBQbG90cwoKKkNvdW50IHBsb3RzKiBkaXNwbGF5IGhvdyBtYW55IHRpbWVzIHR3byBjYXRlZ29yaWNhbCB2YWx1ZXMgYXBwZWFyIHRvZ2V0aGVyIGluIGEgZGF0YXNldC4gRm9yIGluc3RhbmNlLCBpbiB0aGUgY291bnQgcGxvdCBiZWxvdywgd2UgZGlzcGxheSB0aGUgbnVtYmVyIG9mIG9wZW4gaG9zcGl0YWxzIHdpdGggZWFjaCBjb21iaW5hdGlvbiBvZiBPV05FUiBhbmQgVFlQRS4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gQ0FURUdPUklDQUxfVkFSSUFCTEUsIHkgPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9jb3VudCgpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBUWVBFLCB5ID0gT1dORVIpKSArIAogIGdlb21fY291bnQoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSkpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSBhbmQgT3duZXJzaGlwIiwgeCA9ICJUeXBlIiwgeSA9ICJPd25lcnNoaXAiKQpgYGAKCiMjIyMgVGl0bGluZyBhIENvdW50IFBsb3QKCk5vdGUgaG93IEkgdGl0bGVkIG15IHBsb3QgYWJvdmU6ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUgYW5kIE93bmVyc2hpcCIgQ29uc2lkZXIgYWdhaW4gd2hhdCBtYWtlcyBlYWNoIG9ic2VydmF0aW9uIHVuaXF1ZS4gSGVyZSBJIGFtIGNvdW50aW5nIHRoZSBvYnNlcnZhdGlvbnMgYnkgVHlwZSBhbmQgT3duZXJzaGlwLCBhbmQgaW4gb3JkZXIgdG8ga25vdyB3aGF0IEknbSBjb3VudGluZywgSSBuZWVkIHRvIGtub3cgd2hhdCBlYWNoIG9ic2VydmF0aW9uIHJlZmVycyB0by4gQSBnb29kIGZvcm11bGEgZm9yIHRpdGxpbmcgY291bnQgcGxvdHMgaXMgYXMgZm9sbG93czoKCk51bWJlciBvZiBfX19fXyBieSBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIGFuZCBbeS1heGlzIHZhcmlhYmxlIG5hbWVdCgpUaGUgYmxhbmsgc2hvdWxkIGJlIGZpbGxlZCB3aXRoIHlvdXIgdW5pdCBvZiBvYnNlcnZhdGlvbi4gVGhlIFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gc2hvdWxkIGJlIHlvdXIgeC1sYWJlbCBhbmQgW3ktYXhpcyB2YXJpYWJsZSBuYW1lXSBzaG91bGQgYmUgeW91ciB5LWxhYmVsLgoKIyMjIyBXaGF0IGlmIEkgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24/CgpJZiB0aGlzIGlzIHRoZSBjYXNlIEkgd291bGQgZW5jb3VyYWdlIHlvdSB0byBpbmNsdWRlIG9uZSBvZiB0aGUgcXVhbGlmaWVkIHZhcmlhYmxlcyBpbiB0aGUgeCBvciB5LWF4aXMuIEZvciBpbnN0YW5jZSwgaWYgdGhlIHVuaXF1ZSBrZXkgZm9yIHdvcmxkX2hlYWx0aF9lY29uIGlzIGNvdW50cnkgYW5kIHllYXIsIEkgY2FuIGluY2x1ZGUgeWVhciBhcyB0aGUgeS1heGlzIGJlbG93IHRvIHZpc3VhbGl6ZSBob3cgY291bnRzIG9mIG9ic2VydmF0aW9ucyBjaGFuZ2Ugb3ZlciB0aW1lLiAoTm90aWNlIGhvdyB0aGV5IGRvbid0IGluIHRoZSBwbG90IGJlbG93LikgQWx0ZXJuYXRpdmVseSwgaWYgeW91IHdpc2ggdG8gY29tcGFyZSB0d28gY2F0ZWdvcmljYWwgdmFyaWFibGVzIHRoYXQgYXJlIG5vdCBhIHBhcnQgb2YgdGhlIHVuaXF1ZSBrZXksIGJlIHN1cmUgdG8gZmlsdGVyIHRoZSBkYXRhIHNvIHRoYXQgb25seSBvbmUgdmFyaWFibGUgY29uc3RpdHV0ZXMgdGhlIHVuaXF1ZSBrZXkuCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI1J1biB0aGlzIGNvZGUgY2h1bmsuCgp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY29udGluZW50LCB5ID0gYXMuZmFjdG9yKHllYXIpKSkgKyAKICBnZW9tX2NvdW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgQ291bnRyaWVzIGJ5IENvbnRpbmVudCBhbmQgWWVhciIsIHggPSAiQ29udGluZW50IiwgeSA9ICJZZWFyIikKYGBgCgojIyMgU3RhY2tlZCBGcmVxdWVuY3kgUGxvdHMgCgoqU3RhY2tlZCBmcmVxdWVuY3kgcGxvdHMqIGRpc3BsYXkgdGhlIGRpc3RyaWJ1dGlvbiBvZiBudW1lcmljIHZhbHVlcyBpbiBhIHZhcmlhYmxlLCBncm91cGVkIGJ5IGEgY2F0ZWdvcmljYWwgdmFsdWUuIEZvciBpbnN0YW5jZSwgdGhlIHBsb3QgYmVsb3cgZGlzcGxheSB0aGUgZGlzdHJpYnV0aW9uIG9mIGJlZHMgYWNyb3NzIG9wZW4gaG9zcGl0YWxzLCBjYXRlZ29yaXplZCBieSB0aGUgaG9zcGl0YWwgdHlwZS4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gTlVNRVJJQ19WQVJJQUJMRSwgY29sID0gQ0FURUdPUklDQUxfVkFSSUFCTEUpKSArIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxKQoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gQkVEUywgY29sID0gVFlQRSkpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwMCkgKwogIGxhYnModGl0bGUgPSAiRnJlcXVlbmN5IG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBIb3NwaXRhbCBUeXBlIiwgeCA9ICJCZWRzIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbCIsIGNvbCA9ICJUeXBlIikgKyAjIFRvIGFkZCB0aXRsZXMgYW5kIGxhYmVscwogIHRoZW1lX2J3KCkgCmBgYAoKU3RhY2tlZCBmcmVxdWVuY3kgcGxvdHMgd29yayBiZXN0IHdoZW4gY2F0ZWdvcml6aW5nIGJ5IGEgdmFyaWFibGUgd2l0aCAxMCBvciBmZXdlciBkaXN0aW5jdCB2YWx1ZXMuIE90aGVyd2lzZSwgaXQgY2FuIGJlIHRyaWNreSB0byBzZWUgdGhlIGRpZmZlcmVuY2VzIGluIGNvbG9yIGdyYWRhdGlvbnMuIElmIGFsbCBvZiB5b3VyIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBoYXZlIG1vcmUgdGhhbiAxMCBkaXN0aW5jdCB2YWx1ZXMsIG9uZSB0aGluZyB5b3UgbWlnaHQgY29uc2lkZXIgaXMgZmlyc3QgZmlsdGVyaW5nIHlvdXIgZGF0YSB0byBhIGZldyByZXByZXNlbnRhdGl2ZSBjYXRlZ29yaWVzLiBGb3IgaW5zdGFuY2UsIGxldCdzIHNheSB0aGF0IEkgd291bGQgbGlrZSB0byBzZWUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBiZWRzIGluIGhvc3BpdGFscyBhY3Jvc3Mgc3RhdGVzLiBTaW5jZSB0aGVyZSBhcmUgNTcgc3RhdGVzLCBpZiBJIHdlcmUgdG8gY2F0ZWdvcml6ZSB0aGUgZGlzdHJpYnV0aW9uIGJ5IHN0YXRlLCB0aGUgcGxvdCB3b3VsZCBiZSB2ZXJ5IGRpZmZpY3VsdCB0byByZWFkLgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBOVU1FUklDX1ZBUklBQkxFLCBjb2wgPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTLCBjb2wgPSBTVEFURSkpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwMCkgKwogIGxhYnModGl0bGUgPSAiRnJlcXVlbmN5IG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBIb3NwaXRhbCBTdGF0ZSIsIHggPSAiQmVkcyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWwiLCBjb2wgPSAiVHlwZSIpICsgIyBUbyBhZGQgdGl0bGVzIGFuZCBsYWJlbHMKICB0aGVtZV9idygpIApgYGAKCkluIHRoaXMgY2FzZSwgd2UgbWF5IHdpc2ggdG8gZmlyc3QgZmlsdGVyIG91ciBkYXRhIHRvIGEgZmV3IHJlcHJlc2VudGF0aXZlIHN0YXRlcyB1c2luZyAqKiVpbiUqKi4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gTlVNRVJJQ19WQVJJQUJMRSwgY29sID0gQ0FURUdPUklDQUxfVkFSSUFCTEUpKSArIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxKQoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFNUQVRFICVpbiUgKGMoIkNBIiwgIk1BIiwgIk5ZIiwgIkZMIiwgIkxBIikpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTLCBjb2wgPSBTVEFURSkpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwMCkgKwogIGxhYnModGl0bGUgPSAiRnJlcXVlbmN5IG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBIb3NwaXRhbCBTdGF0ZSIsIHggPSAiQmVkcyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWwiLCBjb2wgPSAiVHlwZSIpICsgIyBUbyBhZGQgdGl0bGVzIGFuZCBsYWJlbHMKICB0aGVtZV9idygpIApgYGAKCiMjIyMgVGl0bGluZyBhIFN0YWNrZWQgRnJlcXVlbmN5IFBsb3QKCk5vdGUgaG93IEkgdGl0bGVkIG15IHBsb3QgYWJvdmU6ICJGcmVxdWVuY3kgb2YgQmVkcyBhY3Jvc3MgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IEhvc3BpdGFsIFR5cGUiIENvbnNpZGVyIGFnYWluIHdoYXQgbWFrZXMgZWFjaCBvYnNlcnZhdGlvbiB1bmlxdWUuIEhlcmUgSSBhbSBjb3VudGluZyB0aGUgb2JzZXJ2YXRpb25zIGJ5IG51bWJlciBvZiBCZWRzIGFuZCBIb3NwaXRhbCBUeXBlLiBBIGdvb2QgZm9ybXVsYSBmb3IgdGl0bGluZyBzdGFja2VkIGZyZXF1ZW5jeSBwbG90cyBpcyBhcyBmb2xsb3dzOiAKCkZyZXF1ZW5jeSBvZiBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIGFjcm9zcyBfX19fXyBieSBbY29sIHZhcmlhYmxlIG5hbWVdCgpUaGUgYmxhbmsgc2hvdWxkIGJlIGZpbGxlZCB3aXRoIHlvdXIgdW5pdCBvZiBvYnNlcnZhdGlvbi4gVGhlIFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gc2hvdWxkIGJlIHlvdXIgeC1sYWJlbCwgIkNvdW50IG9mIF9fX19fXyIgKGZpbGxlZCB0aGUgc2FtZSBhcyBhYm92ZSkgc2hvdWxkIGJlIHlvdXIgeS1sYWJlbCwgYW5kIHRoZSBbY29sIHZhcmlhYmxlIG5hbWVdIHNob3VsZCBiZSB5b3VyIGNvbC1sYWJlbC4KCiMjIyMgV2hhdCBpZiBJIGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uPwoKSWYgdGhpcyBpcyB0aGUgY2FzZSBJIHdvdWxkIGVuY291cmFnZSB5b3UgdG8gaW5jbHVkZSBvbmUgb2YgdGhlIHF1YWxpZmllZCB2YXJpYWJsZXMgaW4gdGhlIGNvbCB2YXJpYWJsZS4gRm9yIGluc3RhbmNlLCBpZiB3b3JsZF9oZWFsdGhfZWNvbiBpcyBxdWFsaWZpZWQgYnkgY291bnRyeSBhbmQgeWVhciwgSSBjYW4gaW5jbHVkZSB5ZWFyIGFzIHRoZSBjb2wgdmFyaWFibGUgYmVsb3cgdG8gdmlzdWFsaXplIGhvdyB0aGUgZnJlcXVlbmN5IG9mIGNvdW50cmllcyB3aXRoIHZhcmlvdXMgbGlmZSBleHBlY3RhbmNpZXMgY2hhbmdlcyBvdmVyIHRpbWUuIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBOVU1FUklDX1ZBUklBQkxFLCBjb2wgPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEpCgp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbGlmZV9leHAsIGNvbCA9IGFzLmZhY3Rvcih5ZWFyKSkpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDUpICsKICB0aGVtZV9idygpICsKICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBMaWZlIEV4cGVjdGFuY2llcyBhY3Jvc3MgQ291bnRyaWVzIGJ5IFllYXIiLCB4ID0gIkxpZmUgRXhwZWN0YW5jeSIsIHkgPSAiQ291bnQgb2YgQ291bnRyaWVzIiwgY29sID0gIkxpZmUgRXhwZWN0YW5jeSIpIApgYGAKCj4gTm90ZSB0aGF0IHRoaXMgaXMgb25lIHBsb3QgdGhhdCBpcyBwYXJ0aWN1bGFybHkgc3VzY2VwdGlibGUgdG8gbWlzc2luZyBkYXRhLiBJZiBjZXJ0YWluIGNvdW50cmllcyBkaWQgbm90IHJlcG9ydCBkYXRhIGluIGNlcnRhaW4geWVhcnMsIHRoZSBjb3VudCBvZiBjb3VudHJpZXMgaW4gYSBicmFja2V0IHdpbGwgYXBwZWFyIGxvd2VyLCBub3QgbmVjZXNzYXJpbHkgYmVjYXVzZSBmZXdlciBjb3VudHJpZXMgZmVsbCB3aXRoaW4gYSBjZXJ0YWluIGxpZmUgZXhwZWN0YW5jeSBicmFja2V0LCBidXQgYmVjYXVzZSBmZXdlciBjb3VudHJpZXMgcmVwb3J0ZWQgdGhhdCBsaWZlIGV4cGVjdGFuY3kuIAoKQWx0ZXJuYXRpdmVseSwgeW91IGNvdWxkIHpvb20gaW4gdG8gb25lIHZhbHVlIGluIG9uZSBvZiB5b3VyIHF1YWxpZmllZCB2YXJpYWJsZXMsIGZpbHRlcmluZyB0byBhIHNwZWNpZmljIHN1YnNldCBvZiBvYnNlcnZhdGlvbnMgYW5kIHRoZW4gZGl2aWRlIGJ5IGEgZGlmZmVyZW50IGNhdGVnb3JpY2FsIHZhcmlhYmxlLiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gTlVNRVJJQ19WQVJJQUJMRSwgY29sID0gQ0FURUdPUklDQUxfVkFSSUFCTEUpKSArIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxKQoKd29ybGRfaGVhbHRoX2Vjb24gJT4lIAogIGZpbHRlcih5ZWFyID09IG1heCh5ZWFyLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBsaWZlX2V4cCwgY29sID0gY29udGluZW50KSkgKyAKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gNSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGUgPSAiRnJlcXVlbmN5IG9mIExpZmUgRXhwZWN0YW5jaWVzIGFjcm9zcyBDb3VudHJpZXMgYnkgQ29udGluZW50IGluIDIwMTAiLCB4ID0gIkxpZmUgRXhwZWN0YW5jeSIsIHkgPSAiQ291bnQgb2YgQ291bnRyaWVzIiwgY29sID0gIkNvbnRpbmVudCIpCmBgYAoKIyMjIFBvaW50IHBsb3RzCgoqUG9pbnQgcGxvdHMqIGRpc3BsYXkgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgYW5kIGEgbnVtZXJpYyB2YXJpYWJsZS4gRm9yIGluc3RhbmNlLCB0aGUgcGxvdCBiZWxvdyBkaXNwbGF5cyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhvc3BpdGFsIHR5cGUgYW5kIHRoZSBudW1iZXIgb2YgYmVkcyBhdCB0aGUgaG9zcGl0YWwuIE5vdGFibHksIHVubGlrZSB0aGUgcGxvdHMgd2UgaGF2ZSBiZWVuIHZpZXdpbmcgdW50aWwgbm93LCB3aXRoIHBvaW50IHBsb3RzLCB3ZSBzZWUgYSBwb2ludCBmb3IgZXZlcnkgb2JzZXJ2YXRpb24gaW4gdGhlIGRhdGFzZXQuIEJlY2F1c2UgcG9pbnQgcGxvdHMgZGlzcGxheSBldmVyeSBvYnNlcnZhdGlvbiAocmF0aGVyIHRoYW4gYWdncmVnYXRpbmcgdGhlbSBpbnRvIG90aGVyIHBvbHlnb25zIGFuZCBsaW5lcyksIHRoZXkgYXJlIHBhcnRpY3VsYXJseSBnb29kIGZvciBzZWVpbmcgb3V0bGllcnMgaW4gdGhlIGRhdGEuIEhvd2V2ZXIsIHdpdGggbGFyZ2UgZGF0YXNldHMsIHRoaXMgYWxzbyBjYW4gbWVhbiB0aGF0IHBvaW50cyB3aWxsIG92ZXJsYXAuIE5vdGUgdGhhdCB0aGUgZmlyc3QgcGxvdCBiZWxvdyBleGhpYml0cyBvdmVycGxvdHRpbmcgLSB3aGVuIHRoZSBkYXRhIHJlcHJlc2VudGVkIG9uIGEgcGxvdCBvdmVybGFwcywgbWFraW5nIGl0IGRpZmZpY3VsdCB0byBkaXNjZXJuIG9uZSBwb2ludCBmcm9tIHRoZSBuZXh0LiBUaGVyZSBhcmUgdmFyaW91cyB0b29scyBhdmFpbGFibGUgdG8gZGVhbCB3aXRoIG92ZXItcGxvdHRpbmcuIFlvdSBjYW4gcmVkdWNlIHRoZSBzaXplIG9mIHBvaW50cyBvbiB0aGUgcGxvdCwgaW5jcmVhc2UgdGhlaXIgdHJhbnNwYXJlbmN5LCBvciBzZXQgdGhlbSB0byBzbGlnaHRseSBvZmZzZXQgZWFjaCBvdGhlciAoa25vd24gYXMgYWRkaW5nIGppdHRlcikuIFdlIGRvIGFsbCB0aHJlZSBpbiB0aGUgc2Vjb25kIHBsb3QgYmVsb3cuCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI1J1biB0aGlzIGNvZGUgY2h1bmsuCgojZGYgJT4lIGdncGxvdChhZXMoeCA9IENBVEVHT1JJQ0FMX1ZBUklBQkxFLCB5ID0gTlVNRVJJQ19WQVJJQUJMRSkpICsgZ2VvbV9wb2ludCgpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBUWVBFLCB5ID0gQkVEUykpICsgCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEJlZHMgaW4gSG9zcGl0YWxzIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIk51bWJlciBvZiBCZWRzIikKCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBUWVBFLCB5ID0gQkVEUykpICsgCiAgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjEpICsgI0NoYW5nZSBnZW9tX3BvaW50IHRvIGdlb21faml0dGVyLCByZWR1Y2UgdGhlIHNpemUsIGFkZCB0cmFuc3BhcmVuY3kgZm9yIG92ZXJwbG90dGluZwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgQmVkcyBpbiBIb3NwaXRhbHMgYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiTnVtYmVyIG9mIEJlZHMiKQoKYGBgCgpOb3RpY2UgdGhhdCB0aGluayBibGFjayBsaW5lIGluIHRoZSBjb2x1bW4gZm9yIENyaXRpY2FsIEFjY2VzcyBob3NwaXRhbHMuIEJhc2VkIG9uIHdoYXQgd2UndmUgbGVhcm5lZCBvZiBjcml0aWNhbCBhY2Nlc3MgaG9zcGl0YWxzLCBjYW4geW91IHN1cm1pc2Ugd2hhdCBudW1iZXIgdGhleSBhcmUgY2x1c3RlcmVkIGF0PyAKCmBgYHtyIGV2YWw9RkFMU0V9CigrLjI1IHBvaW50cyBvbiBsYWIgaWYgeW91IGNhbiByZXNwb25kIGNvcnJlY3RseSBoZXJlLikKCkNyaXRpY2FsIGFjY2VzcyBob3NwaXRhbHMgaGF2ZSBtYW55IGd1aWRlbGluZXMgdGhleSBoYXZlIHRvIGZvbGxvdyBpbiBvcmRlciB0byByZWNlaXZlIGZ1bmRpbmcuIEluIHRoaXMgY2FzZSwgdGhlIGJsYWNrIGxpbmUgaW4gdGhlIGNvbHVtbiByZXByZXNlbnRzIHRoZSBjbHVzdGVyIG9mIGJlZHMgYXQgdGhlIHZhbHVlIDI1LiBUaGF0IGlzIGJlY2F1c2UgY3JpdGljYWwgYWNjZXNzIGhvc3BpdGFscyBjYW4ndCBoYXZlIG1vcmUgdGhhbiAyNSBiZWRzIGluIG9yZGVyIHRvIGFkaGVyZSB0byBndWlkZWxpbmVzIGFuZCByZWNlaXZlIGZ1bmRpbmcuCgpgYGAKCiMjIyMgVGl0bGluZyBhIFBvaW50IFBsb3QKCk5vdGUgaG93IEkgdGl0bGVkIG15IHBsb3QgYWJvdmU6ICJOdW1iZXIgb2YgQmVkcyBpbiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIgSGVyZSBJIGFtIGRpc3BsYXlpbmcgdGhlIG51bWJlciBvZiBiZWRzIGJ5IFR5cGUuIEEgZ29vZCBmb3JtdWxhIGZvciB0aXRsaW5nIHBvaW50IHBsb3RzIGlzIGFzIGZvbGxvd3M6CgpOdW1iZXIvTWVhc3VyZSBvZiBbeS1heGlzIHZhcmlhYmxlIG5hbWVdIGluIF9fX19fIGJ5IFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gCgpUaGUgYmxhbmsgc2hvdWxkIGJlIGZpbGxlZCB3aXRoIHlvdXIgdW5pdCBvZiBvYnNlcnZhdGlvbi4gVGhlIFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gc2hvdWxkIGJlIHlvdXIgeC1sYWJlbCBhbmQgIk51bWJlci9NZWFzdXJlIG9mIFt5LWF4aXMgdmFyaWFibGUgbmFtZV0iIHNob3VsZCBiZSB5b3VyIHktbGFiZWwuCgojIyMjIFdoYXQgaWYgSSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbj8KCklmIHRoaXMgaXMgdGhlIGNhc2UgSSB3b3VsZCBlbmNvdXJhZ2UgeW91IHRvIGZpbHRlciB5b3VyIGRhdGEgYXMgeW91IGhhdmUgYmVlbiBkb2luZyBlbHNld2hlcmUuIEZvciBpbnN0YW5jZSBpZiB3b3JsZF9oZWFsdGhfZWNvbiBpcyBxdWFsaWZpZWQgYnkgY291bnRyeSBhbmQgeWVhciwgSSBjYW4gZmlsdGVyIHRvIHRoZSBtb3N0IHJlY2VudCB5ZWFyIGJlZm9yZSBjcmVhdGluZyBhIHBvaW50IHBsb3Qgb2YgdGhlIHByaXZhdGUgc2hhcmUgb2YgaGVhbHRoIHNwZW5kaW5nIGJ5IGNvbnRpbmVudC4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCndvcmxkX2hlYWx0aF9lY29uICU+JSAKICBmaWx0ZXIoeWVhciA9PSBtYXgoeWVhciwgbmEucm0gPSBUUlVFKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29udGluZW50LCB5ID0gcHJpdl9zaGFyZV9oZWFsdGhfc3ApKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGFscGhhID0gMC44KSArICAKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkgKwogIGxhYnModGl0bGUgPSAiUHJpdmF0ZSBTaGFyZSBvZiBIZWFsdGggU3BlbmRpbmcgaW4gQ291bnRyaWVzIGJ5IENvbnRpbmVudCBpbiAyMDEwIiwgeCA9ICJDb250aW5lbnQiLCB5ID0gIlByaXZhdGUgU2hhcmUgb2YgSGVhbHRoIFNwZW5kaW5nIikgCmBgYAoKIyMjIFNjYXR0ZXJwbG90cwoKKlNjYXR0ZXJwbG90cyogZGlzcGxheSB0aGUgcmVsYXRpb25zaGlwIG9yIGNvcnJlbGF0aW9uIGJldHdlZW4gdHdvIG51bWVyaWMgdmFyaWFibGVzLiBGb3IgaW5zdGFuY2UsIGJlbG93IHdlIHBsb3QgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBCRURTIHZhcmlhYmxlIGFuZCB0aGUgUE9QVUxBVElPTiB2YXJpYWJsZSBpbiB0aGUgaG9zcGl0YWxzIGRhdGFzZXQuIAoKVGhlcmUgYXJlIGRpZmZlcmVudCB3YXlzIHRvIGNoYXJhY3Rlcml6ZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gdmFyaWFibGVzIGluIGRhdGEuIFdlIG1heSBjb25zaWRlciB0aGUgKnN0cmVuZ3RoKiBvZiBhIGNvcnJlbGF0aW9uLCB0aGUgKnNoYXBlKiBvZiBhIGNvcnJlbGF0aW9uLCBhbmQgd2hldGhlciB0aGUgY29ycmVsYXRpb24gaXMgcG9zaXRpdmUgb3IgbmVnYXRpdmUuIAoKKiBUd28gdmFyaWFibGVzIGluIGEgc2NhdHRlcnBsb3QgY2FuIGJlIHNhaWQgdG8gaGF2ZSBhIHN0cm9uZyBjb3JyZWxhdGlvbiB3aGVuIHBvaW50cyBhcmUgY2x1c3RlcmVkIGNsb3NlbHkgdG8gYSBjZW50cmFsIGxpbmUgb3IgY3VydmUuIFRoZSBtb3JlIHNjYXR0ZXJlZCB0aHJvdWdob3V0IHRoZSBwbG90IHRoZSBwb2ludHMgYXJlLCB0aGUgd2Vha2VyIHRoZSBjb3JyZWxhdGlvbi4KKiBUd28gdmFyaWFibGVzIGluIGEgc2NhdHRlcnBsb3QgY2FuIGJlIHNhaWQgdG8gaGF2ZSBhIGxpbmVhciBjb3JyZWxhdGlvbiB3aGVuIHRoZSBzY2F0dGVycGxvdCB0ZW5kcyB0byBwcm9kdWNlIGEgc3RyYWlnaHQgbGluZS4gVGhpcyBtZWFucyB0aGF0IHRoZSByYXRlIG9mIGNoYW5nZSBiZXR3ZWVuIHR3byB2YXJpYWJsZXMgaXMgc3RlYWR5LiBIb3dldmVyLCB3aGVuIGEgc2NhdHRlcnBsb3QgcHJvZHVjZXMgYSBjdXJ2ZSwgdGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgcmF0ZSBvZiBjaGFuZ2UgYmV0d2VlbiB0d28gdmFyaWFibGVzIGlzIG5vdCBhcyBjb25zdGFudC4KKiBUd28gdmFyaWFibGVzIGluIGEgc2NhdHRlcnBsb3QgY2FuIGJlIHNhaWQgdG8gaGF2ZSBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uIHdoZW4gdGhlIHBvaW50cyBtb3ZlIHVwd2FyZCBmcm9tIHRoZSBib3R0b20gbGVmdCBjb3JuZXIgdG93YXJkcyB0aGUgdG9wIHJpZ2h0IGNvcm5lciBvZiB0aGUgcGxvdC4gVGhpcyBtZWFucyB0aGF0IGFzIHZhbHVlcyBpbiB2YXJpYWJsZSBpbmNyZWFzZXMsIHRoZSB2YWx1ZXMgaW4gdGhlIG90aGVyIHZhcmlhYmxlIGFsc28gaW5jcmVhc2UuIFdoZW4gcG9pbnRzIG1vdmUgZG93bndhcmQgZnJvbSB0aGUgdG9wIGxlZnQgY29ybmVyIHRvIHRoZSBib3R0b20gcmlnaHQgY29ybmVyIG9mIHRoZSBwbG90LCB3ZSBjYW4gc2F5IHRoYXQgdGhlIHZhcmlhYmxlcyBuZWdhdGl2ZWx5IGNvcnJlbGF0aW9uLiBUaGlzIG1lYW5zIHRoYXQgYXMgdmFsdWVzIGluIHZhcmlhYmxlIGluY3JlYXNlcywgdGhlIHZhbHVlcyBpbiB0aGUgb3RoZXIgdmFyaWFibGUgZGVjcmVhc2VzLgoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKI2dncGxvdChkZiwgYWVzKHggPSBOVU1FUklDX1ZBUklBQkxFLCB5ID0gTlVNRVJJQ19WQVJJQUJMRSkpICsgZ2VvbV9wb2ludCgpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTLCB5ID0gUE9QVUxBVElPTikpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgdGhlbWVfYncoKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBIb3NwaXRhbCBCZWRzIGFuZCBQb3B1bGF0aW9uIGluIHRoZSBVUyIsIHggPSAiQmVkcyIsIHkgPSAiUG9wdWxhdGlvbiIpIApgYGAKCj4gTm90ZSB0aGF0IHRoaXMgcGxvdCBoYXMgYSBzdHJvbmcsIGxpbmVhciBwb3NpdGl2ZSBjb3JyZWxhdGlvbi4gQXMgQkVEUyBpbmNyZWFzZSBpbiB0aGlzIHZhcmlhYmxlLCBQT1BVTEFUSU9OIGFsc28gdGVuZHMgdG8gaW5jcmVhc2UuIAoKIyMjIyBUaXRsaW5nIGEgU2NhdHRlcnBsb3QKCk5vdGUgaG93IEkgdGl0bGVkIG15IHBsb3QgYWJvdmU6ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBIb3NwaXRhbCBCZWRzIGFuZCBQb3B1bGF0aW9uIGluIHRoZSBVUyIgQSBnb29kIGZvcm11bGEgZm9yIHRpdGxpbmcgc2NhdHRlcnBsb3RzIGlzIGFzIGZvbGxvd3M6CgpSZWxhdGlvbnNoaXAgYmV0d2VlbiBfX19fXyBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIGFuZCBbeS1heGlzIHZhcmlhYmxlIG5hbWVdIAoKVGhlIGJsYW5rIHNob3VsZCBiZSBmaWxsZWQgd2l0aCB5b3VyIHVuaXQgb2Ygb2JzZXJ2YXRpb24uIFRoZSBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIHNob3VsZCBiZSB5b3VyIHgtbGFiZWwgYW5kIFt5LWF4aXMgdmFyaWFibGUgbmFtZV0iIHNob3VsZCBiZSB5b3VyIHktbGFiZWwuCgojIyMjIFdoYXQgaWYgSSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbj8KCklmIHRoaXMgaXMgdGhlIGNhc2UgSSB3b3VsZCBlbmNvdXJhZ2UgeW91IHRvIGZpbHRlciB5b3VyIHBsb3QgdG8gb25lIHZhbHVlIGluIG9uZSBvZiB5b3VyIHF1YWxpZmllZCB2YXJpYWJsZXMuIEZvciBpbnN0YW5jZSBpZiB3b3JsZF9oZWFsdGhfZWNvbiBpcyBxdWFsaWZpZWQgYnkgY291bnRyeSBhbmQgeWVhciwgSSBjYW4gZmlsdGVyIHRvIHRoZSBtb3N0IHJlY2VudCB5ZWFyIGJlZm9yZSBjcmVhdGluZyBhIHBvaW50IHBsb3Qgb2YgdGhlIHByaXZhdGUgc2hhcmUgb2YgaGVhbHRoIHNwZW5kaW5nIGJ5IGNvbnRpbmVudC4KCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQojUnVuIHRoaXMgY29kZSBjaHVuay4KCiNnZ3Bsb3QoZGYsIGFlcyh4ID0gTlVNRVJJQ19WQVJJQUJMRSwgeSA9IE5VTUVSSUNfVkFSSUFCTEUpKSArIGdlb21fcG9pbnQoKQoKd29ybGRfaGVhbHRoX2Vjb24gJT4lIAogIGZpbHRlcih5ZWFyID09IG1heCh5ZWFyLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0b3RfaGVhbHRoX3NwX3BwLCB5ID0gbGlmZV9leHAsIHNpemUgPSBwb3AsIGNvbCA9IGNvbnRpbmVudCkpICsgCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzdHJva2UgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBDb3VudHJ5IFRvdGFsIEhlYWx0aCBTcGVuZGluZyBQZXIgUGVyc29uIGFuZCBMaWZlIEV4cGVjdGFuY3kiLCB4ID0gIlRvdGFsIEhlYWx0aCBTcGVuZGluZyBQZXIgUGVyc29uIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiLCBzaXplID0gIlBvcHVsYXRpb24iLCBjb2wgPSAiQ29udGluZW50IikgKyAKICB0aGVtZV9idygpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDEsIDEwKSwgbGFiZWxzID0gc2NhbGVzOjpjb21tYSkKYGBgCgo+IE5vdGUgdGhhdCB0aGlzIHBsb3QgaGFzIGEgd2Vha2VyLCBjdXJ2aWxpbmVhciwgcG9zaXRpdmUgY29ycmVsYXRpb24uIEFzIFRvdGFsIEhlYWx0aCBTcGVuZGluZyBwZXIgUGVyc29uIGluY3JlYXNlcyBpbiB0aGlzIHZhcmlhYmxlLCBMaWZlIEV4cGVjdGFuY3kgYWxzbyB0ZW5kcyB0byBpbmNyZWFzZSwgYnV0IHRoZSByYXRlIG9mIGNoYW5nZSBhdCB3aGljaCBpdCBpbmNyZWFzZXMgaXMgbm90IGNvbnN0YW50LiAgCgpIYXZlIHlvdSBoZWFyZCB0aGUgcXVpcCAiQ29ycmVsYXRpb24gZG9lcyBub3QgZXF1YWwgY2F1c2F0aW9uIj8gVGhpcyBpcyBwYXJ0aWN1bGFybHkgaW1wb3J0YW50IHRvIGNvbnNpZGVyIGhlcmUuIEluIGxhYiA3LCB3ZSB3aWxsIGV4YW1pbmUgc29tZSBjb25mb3VuZGluZyB2YXJpYWJsZXMgdGhhdCBtYXkgYmUgbWVkaWF0aW5nIGhvdyB2YWx1ZXMgYXBwZWFyIHRvIGNvcnJlbGF0ZSBpbiBvdXIgZGF0YS4gRm9yIG5vdywgaXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IGp1c3QgYmVjYXVzZSB3ZSBzZWUgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRvdGFsIGhlYWx0aCBzcGVuZGluZyBhbmQgbGlmZSBleHBlY3RhbmN5IGRvZXMgbm90IG1lYW4gdGhhdCBpbmNyZWFzaW5nIHRvdGFsIGhlYWx0aCBzcGVuZGluZyBpbiBhIGNvdW50cnkgKipjYXVzZXMqKiBsaWZlIGV4cGVjdGFuY3kgdG8gaW5jcmVhc2UuIFRoaXMgaXMgb2YgY291cnNlIGEgY29tcGxleCBpc3N1ZSB3aXRoIGxvdHMgb2Ygb3RoZXIgdmFyaWFibGVzIGludm9sdmVkLiAKCiMjIyBQcm9kdWNlIHR3byBwbG90cyB0aGF0IHJlcHJlc2VudCBjby12YXJpYXRpb24gaW4geW91ciBkYXRhc2V0LiAKCllvdSBuZWVkIG5vdCBpbmNsdWRlIGV2ZXJ5IHBsb3QgSSBkZXNjcmliZWQgYWJvdmUuIEJlIHN1cmUgdG8gem9vbSBpbiBvciBvdXQgb24geW91ciBkYXRhIGlmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbi4gCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KCiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gTlVNRVJJQ19WQVJJQUJMRSwgY29sID0gQ0FURUdPUklDQUxfVkFSSUFCTEUpKSArIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxKQoKCmlwcHMgJT4lIAogIGZpbHRlcihEUkcuRGVmaW5pdGlvbiAlaW4lIChjKCIzMTMgLSBDaGVzdCBQYWluIiwgIjgxMyAtIENPQUdVTEFUSU9OIERJU09SREVSUyIsICIzMTIgLSBTWU5DT1BFICYgQ09MTEFQU0UiLCAiNjUyIC0gS0lETkVZIFRSQU5TUExBTlQiLCAiMDY5IC0gVFJBTlNJRU5UIElTQ0hFTUlBIikpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBBdmVyYWdlLlRvdGFsLlBheW1lbnRzLCBjb2wgPSBEUkcuRGVmaW5pdGlvbikpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDIwMDAwKSArCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgQXZlcmFnZSBUb3RhbCBQYXltZW50cyBhY3Jvc3MgSG9zcGl0YWxzIGJ5IERpYWdub3NpcyIsIHggPSAiQXZlcmFnZSBUb3RhbCBQYXltZW50cyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIERpYWdub3NlcyIsIGNvbCA9ICJEaWFnbm9zaXMgVHlwZSIpICsgCiAgdGhlbWVfYncoKSAKCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGlzIGFuYWx5c2lzIGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gQmUgc3VyZSB0byBhZGp1c3QgeW91ciBwbG90IGFib3ZlIHRvIHJlZmxlY3QgdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpXaGF0IGVsc2Ugd291bGQgd2UgbmVlZCB0byBrbm93IHRvIGZ1bGx5IGFkZHJlc3MgdGhpcyBxdWVzdGlvbj8gSGVyZSB5b3UgbWF5IGNvbnNpZGVyIHdoYXQgeW91IGtub3cgYWJvdXQgaG93IHRoaXMgZGF0YXNldCB3YXMgcHJvZHVjZWQgYW5kIGl0cyBsaW1pdGF0aW9ucy4KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gdGhpcyBwbG90PwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQojRmlsbCB0aGUgY29kZSBmb3IgcGxvdCAyIGhlcmUuIEFkZCBhIHRpdGxlIGFuZCBsYWJlbHMgdG8geW91ciBwbG90cy4gQmUgc3VyZSB0byBhZGp1c3QgZm9yIG92ZXJwbG90dGluZy4KCmlwcHMgJT4lIAogIGZpbHRlcihEUkcuRGVmaW5pdGlvbiAlaW4lIChjKCIzMTMgLSBDaGVzdCBQYWluIiwgIjgxMyAtIENPQUdVTEFUSU9OIERJU09SREVSUyIsICIzMTIgLSBTWU5DT1BFICYgQ09MTEFQU0UiLCAiNjUyIC0gS0lETkVZIFRSQU5TUExBTlQiLCAiMDY5IC0gVFJBTlNJRU5UIElTQ0hFTUlBIiwgIjAzOCAtIEVYVFJBQ1JBTklBTCBQUk9DRURVUkVTIFcgQ0MiLCAiNDcyIC0gQ0VSVklDQUwgU1BJTkFMIEZVU0lPTiBXIENDIiwgIjU1MSAtIE1FRElDQUwgQkFDSyBQUk9CTEVNUyBXIE1DQyIsICI2MzcgLSBESUFCRVRFUyBXIE1DQyIpKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRFJHLkRlZmluaXRpb24gLCB5ID0gQXZlcmFnZS5Ub3RhbC5QYXltZW50cykpICsgCiAgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjEpICsgI0NoYW5nZSBnZW9tX3BvaW50IHRvIGdlb21faml0dGVyLCByZWR1Y2UgdGhlIHNpemUsIGFkZCB0cmFuc3BhcmVuY3kgZm9yIG92ZXJwbG90dGluZwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKSArCiAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIFRvdGFsIFBheW1lbnRzIGFjcm9zcyBIb3NwaXRhbHMgYnkgRGlhZ25vc2lzIiwgeCA9ICJEaWFnbm9zaXMgVHlwZSIsIHkgPSAiQXZlcmFnZSBUb3RhbCBQYXltZW50cyIpCgoKYGBgCgpXaGF0IHF1ZXN0aW9uIG1pZ2h0IHRoaXMgYW5hbHlzaXMgaGVscCB0byBhZGRyZXNzPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkFyZSB0aGVyZSBhbnkgb3RoZXIgdmFyaWFibGVzIGluIHlvdXIgZGF0YXNldCB0aGF0IHlvdSBuZWVkIHRvIHRha2UgaW50byBjb25zaWRlcmF0aW9uIGJlZm9yZSBkaXJlY3RpbmcgdGhpcyBhbmFseXNpcyB0b3dhcmRzIGFuc3dlcmluZyB0aGF0IHF1ZXN0aW9uPyBJbiBvdGhlciB3b3JkcywgZG8geW91IG5lZWQgdG8gem9vbSBpbnRvIGFueSBzcGVjaWZpYyBhcmVhcyBvZiB0aGUgZGF0YXNldCAoYnkgZmlsdGVyaW5nKSBpbiBvcmRlciB0byBhcHByb3ByaWF0ZWx5IGFkZHJlc3MgdGhpcyBxdWVzdGlvbj8gSWYgc28sIHdoaWNoPyBCZSBzdXJlIHRvIGFkanVzdCB5b3VyIHBsb3QgYWJvdmUgdG8gcmVmbGVjdCB0aGlzLgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoYXQgZWxzZSB3b3VsZCB3ZSBuZWVkIHRvIGtub3cgdG8gZnVsbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBIZXJlIHlvdSBtYXkgY29uc2lkZXIgd2hhdCB5b3Uga25vdyBhYm91dCBob3cgdGhpcyBkYXRhc2V0IHdhcyBwcm9kdWNlZCBhbmQgaXRzIGxpbWl0YXRpb25zLgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoYXQgaW5zaWdodCBjYW4geW91IGRyYXcgZnJvbSB0aGlzIHBsb3Q/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKIyMgU3RhcnQgYSBzaGlueSBhcHAuCgpBdCB0aGlzIHBvaW50IGluIHRoZSBxdWFydGVyLCB3ZSBhcmUgcHJlcGFyZWQgdG8gc3RhcnQgcGllY2luZyB0b2dldGhlciBhIGRhc2hib2FyZCBmb3IgZGlzcGxheWluZyB0aGUgZGF0YS4gU2hpbnkgQXBwcyBoYXZlIHR3byBjb21wb25lbnRzIC0gYSBmcm9udCBlbmQgKHVpKSwgYW5kIGEgYmFja2VuZCAoc2VydmVyKS4gT24gdGhlIGZyb250IGVuZCwgd2Ugd2lsbCBiZSBjb2RpbmcgaG93IHdlIHdhbnQgb3VyIGRhdGEgZGlzcGxheWVkLiAqKkZvciB0aGlzIHdlZWssIHRoZSBvbmx5IHRoaW5nIHlvdSBuZWVkIHRvIGRvIG9uIHRoZSBmcm9udCBlbmQgaXMgZmlsbCBpbiB5b3VyIHRpdGxlLioqIE9uIHRoZSBiYWNrZW5kLCB3ZSB3aWxsIGJlIGNvZGluZyBvdXIgZGF0YSBhbmFseXNpcy4gCgpGaWxsIGluIHlvdXIgdGl0bGUgaW4gdGhlIFVJLiBMZWF2ZSBldmVyeXRoaW5nIGVsc2UgdGhlIHNhbWUuCgpgYGB7cn0KI0ZvbGxvdyBpbnN0cnVjdGlvbnMgdG8gZmlsbCBjb2RlIGJldHdlZW4gY2FwaXRhbGl6ZWQgc2VjdGlvbnMgYW5kIHRoZW4gcnVuIHRoZSBjb2RlIGNodW5rLgoKdWkgPC0gZGFzaGJvYXJkUGFnZSgKICAKICAjUkVQTEFDRSAnVElUTEUgSEVSRScgQkVMT1cgV0lUSCBZT1VSIE9XTiBUSVRMRQogIGRhc2hib2FyZEhlYWRlcih0aXRsZSA9ICJNZWRpY2FyZSBEYXRhIiksCiAgI1JFUExBQ0UgJ1RJVExFIEhFUkUnIEFCT1ZFIFdJVEggWU9VUiBPV04gVElUTEUKICAKICBkYXNoYm9hcmRTaWRlYmFyKAogICAgI2lucHV0cyB3aWxsIGdvIGhlcmUgZXZlbnR1YWxseSBidXQgbm90IG5vdy4gCiAgKSwKICAKICBkYXNoYm9hcmRCb2R5KAogICAgICBib3gocGxvdE91dHB1dCgicGxvdDEiKSksCiAgICAgIGJveChwbG90T3V0cHV0KCJwbG90MiIpKQogICkKKQpgYGAKClJlcGxhY2UgbXkgcGxvdHMgaW4gdGhlIGNvZGUgYmVsb3cgd2l0aCB0d28gb2YgdGhlIHBsb3RzIHRoYXQgeW91IGNyZWF0ZWQgaW4gdGhpcyBsYWIuIAoKYGBge3J9CiNGb2xsb3cgaW5zdHJ1Y3Rpb25zIHRvIGZpbGwgY29kZSBiZXR3ZWVuIGNhcGl0YWxpemVkIHNlY3Rpb25zIGFuZCB0aGVuIHJ1biB0aGUgY29kZSBjaHVuay4KCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0LCBzZXNzaW9uKSB7CiAgCiAgb3V0cHV0JHBsb3QxIDwtIHJlbmRlclBsb3QoewogICNSRVBMQUNFIEJFTE9XIFdJVEggWU9VUiBPV04gUExPVAogICAgaG9zcGl0YWxzICU+JSAKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogICAgICBnZ3Bsb3QoYWVzKHggPSBUWVBFKSkgKyAKICAgICAgZ2VvbV9iYXIoKSArCiAgICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBUeXBlIiwgeCA9ICJUeXBlIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArIAogICAgICB0aGVtZV9idygpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpIAogICNSRVBMQUNFIEFCT1ZFIFdJVEggWU9VUiBPV04gUExPVAogICAgCiAgfSkKICAKICBvdXRwdXQkcGxvdDIgPC0gcmVuZGVyUGxvdCh7CiAgI1JFUExBQ0UgQkVMT1cgV0lUSCBZT1VSIE9XTiBQTE9UCiAgICBob3NwaXRhbHMgJT4lIAogICAgICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgICAgIGdncGxvdChhZXMoeCA9IFRZUEUpKSArIAogICAgICBnZW9tX2JhcigpICsKICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgCiAgI1JFUExBQ0UgQUJPVkUgV0lUSCBZT1VSIE9XTiBQTE9UIAogIH0pCiAgCn0KYGBgCgpgYGB7ciByZXN1bHRzID0gJ2hpZGUnfQojUnVuIHRoaXMgY29kZSBjaHVuayB0byBzZWUgeW91ciBTaGlueSBhcHAgaW4gYWN0aW9uLiAKCnNoaW55QXBwKHVpLCBzZXJ2ZXIpCmBgYAoKV2hlbiB5b3Uga25pdCB0aGlzIG5vdGVib29rLCB5b3UgbWF5IGdldCBhIHByb21wdCBhc2tpbmcgd2hldGhlciB5b3Ugd291bGQgcHJlZmVyIHRvIHJlbmRlciBhbmQgcnVuIHRoaXMgZG9jdW1lbnQgYXMgU2hpbnkuIENsaWNrIE5vLiBXZSB3aWxsIGJlIGxlYXZpbmcgdGhpcyBub3RlYm9vayBpbiBhIEhUTUwgZG9jdW1lbnQgZm9ybWF0LiAKCg==